兩種數據消費方式:pull與push,陰與陽

pull和push,是在軟件中消費數據的兩種方式,它們描述了數據生產者(或持有者)數據消費者之間是如何通信的。編程

咱們能夠用一個現實生活中的例子來理解pull與push:
你某天想要閱讀新聞,因而打開瀏覽器,輸入新聞網站的地址,敲下回車,因而新聞內容展示在你的眼前。這是一個pull模型;
你也能夠,下載一個新聞App,設置消息推送功能,讓它時不時向你推送重要的新聞。這是一個push模型。瀏覽器

pull系統

在pull系統中,數據消費者決定本身什麼時候請求並接收數據;數據持有者只能被動地響應請求。服務器

編程語言的函數機制就是pull系統的例子。函數是數據生產者,調用者是數據消費者。調用者在本身須要的時候,調用函數,從函數中「拉」出一個結果,即let result = func(args);網絡

JavaScript的Generator function則是pull系統的又一個範例,只不過消費者能夠屢次pull,依次拿出順序有關的多個結果:app

function* generator(i) {
  yield i;
  yield i + 10;
}
const gen = generator(10);
const result1 = gen.next().value;
const result2 = gen.next().value;

push系統

在push系統中,數據生產者決定什麼時候向消費者推送數據。數據消費者不知道什麼時候會收到數據更新。異步

Promise是一個push系統,它的數據生產者是Promise中封裝的異步邏輯,數據消費者則是then中的callback函數。生產者決定什麼時候通知消費者。Promise生產者只能給消費者推送一次數據。編程語言

RxJS的Observable也是一個push系統,它的生產者能給消費者推送屢次數據。ide

對比總結

pull與push的特色對比總結以下:函數

生產者 消費者
pull 被動。收到請求時返回數據 主動。決定什麼時候請求數據
push 主動。決定什麼時候推送數據 被動。響應數據的更新

二者的典型範例總結以下:網站

單結果 多結果
pull Function Iterator (Generator)
push Promise Observable

pull與push,陰與陽

若是從上面的微觀的視角來看Promise,Promise自己確實是一個典型的push模型。可是若是從宏觀的視角來看如下這段代碼:

// 在視圖控制器中的某段代碼:
requestServer().then((data) => {
    view.update(data);
});

// 等價於:
const data = await requestServer();
view.update(data);

又未嘗不是一種pull模型呢?畢竟視圖控制器是數據消費者,它主動從服務器(數據生產者)請求數據並使用。

再換一個視角,若是從View的角度看,它被視圖控制器通知新數據的到來,View本身只能被動地對數據更新產生反應。這難道不是一種push模型嗎?

再換一個視角,上面的這段視圖控制器代碼是何時執行的呢?它總不可能在程序啓動的時候運行一次就完成任務了吧?這段代碼一定也處在某個事件響應函數中(好比某個按鈕的點擊事件回調),或者某個組件生命週期鉤子中(好比onMounted)。那麼它做爲一個事件響應函數,是否是一定處於一個push系統中?

再換一個視角,在requestServer中,向服務器發送請求的時候,底層須要經過DNS系統來解析域名,這個過程是pull模型,即let ip = resolveDNS('www.server.com');

再換一個視角,在操做系統底層,當服務器響應從網絡中到來的時候,操做系統喚醒了對應的線程,對數據進行使用。這個過程又是push模型。

能夠看到,push與pull,它們做爲編碼模型的兩種選擇,是相互競爭的,可是若是你站在不一樣的抽象層次上,老是能發現另外一方的身影。這種「你中有我,我中有你,既相互競爭,又相互依存」的關係,像極了古代中國的哲學思想:陰陽
陰陽.jpg

參考資料

相關文章
相關標籤/搜索