1. 程式人生 > >非同步程式設計:When.js快速上手

非同步程式設計:When.js快速上手

提醒:本文最後更新於 2028 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

前些天我在團內做了一個關於AngularJS的分享。由於AngularJS大量使用Promise,所以我把基於Promise的非同步程式設計也一併介紹了下。很多東西都是一帶而過,這裡再記錄下。

AngularJS內建的是Kris Kowal的Q框架,我介紹的是自己用得更多的cujoJS的when.js,兩者都是Promises/A規範的實現。when.js很小,壓縮後只有數kb,gzip後的大小几乎可以忽略。在Node和瀏覽器環境裡都可以使用when.js,唯一需要注意的是:在瀏覽器使用時,要先加幾行程式碼,再引入js檔案。

首先,我們看一小段程式碼(在瀏覽器中預覽):

var getData = function(callback) {
    $.getJSON(api, function(data){
        callback(data[0]);
    });
}

var getImg = function(src, callback) {
    var img = new Image();

    img.onload = function() {
        callback(img);
    };

    img.src = src;
}

var showImg = function
(img)
{ $(img).appendTo($('#container')); } getData(function(data) { getImg(data, function(img) { showImg(img); }); });

這段程式碼完成了三個任務:1)獲取資料;2)載入圖片;3)顯示圖片,其中,任務1和2是非同步,3是同步,使用的是最常見的callback機制來處理非同步邏輯,好處是淺顯易懂,缺點是強耦合、不直觀、處理異常麻煩等等。

另外一種常見的實現非同步程式設計的方案是事件監聽器,例如使用QWrap的CustEvent,讓任務成功時fireEvent,那麼註冊了這個Event的監聽器就可以收到這個事件,並收到事件傳遞過來的資料,Dom標準事件也是採用的這種形式。這種方案也很好理解,程式碼從略。事件監聽可以解耦,可以繫結任意多個監聽器,但是依然不直觀,而且事件發生之後再繫結的監聽器也得不到觸發。

我們嘗試用when.js改寫下這段程式碼(在瀏覽器中預覽):

var getData = function() {
    var deferred = when.defer();

    $.getJSON(api, function(data){
        deferred.resolve(data[0]);
    });

    return deferred.promise;
}

var getImg = function(src) {
    var deferred = when.defer();

    var img = new Image();

    img.onload = function() {
        deferred.resolve(img);
    };

    img.src = src;

    return deferred.promise;
}

var showImg = function(img) {
    $(img).appendTo($('#container'));
}

getData()
.then(getImg)
.then(showImg);

看最後三行程式碼,是不是一目瞭然,非常的語義化?來看下改寫後的任務1、2多了些什麼:

var deferred = when.defer();

定義了一個deferred物件。

deferred.resolve(data);

在非同步獲取資料完成時,把資料作為引數,呼叫deferred物件的resolve方法。

return deferred.promise;

返回了deferred物件的promise屬性。

在Promises/A規範中,每個任務都有三種狀態:預設(pending)、完成(fulfilled)、失敗(rejected)。

  • 預設狀態可以單向轉移到完成狀態,這個過程叫resolve,對應的方法是deferred.resolve(promiseOrValue);
  • 預設狀態還可以單向轉移到失敗狀態,這個過程叫reject,對應的方法是deferred.reject(reason);
  • 預設狀態時,還可以通過deferred.notify(update)來宣告任務執行資訊,如執行進度;
  • 狀態的轉移是一次性的,一旦任務由初始的pending轉為其他狀態,就會進入到下一個任務的執行過程中。

有人可能會覺得奇怪:改變任務狀態的resolve和reject方法是定義在deferred物件上,但最後返回的卻是deferred的promise屬性。這麼做一是因為規範就是這麼定的,二是可以防止任務狀態被外部改變。

then有三個引數,分別是onFulfilled、onRejected、onProgress,通過這三個引數,就可以指定上一個任務在resolve、reject和notify時該如何處理。例如上一個任務被resolve(data),onFulfilled函式就會被觸發,data作為它的引數;被reject(reason),那麼onRejected就會被觸發,收到reason。任何時候,onFulfilled和onRejected都只有其一可以被觸發,並且只觸發一次;onProgress顧名思義,每次notify時都會被呼叫。下面是reject和notify的用法(在瀏覽器中預覽):

function run() {
    var deferred = when.defer();
    var start = 1, end = 100;

    (function() {
        if(start <= end) {
            deferred.notify(start++);
            setTimeout(arguments.callee, 50);
        } else {
            deferred.reject('time out!');
        }
    })();

    return deferred.promise;
}

run().then(undefined,
    function(reason) {
        alert(reason);
    }, function(s) {
        document.getElementById('output').innerHTML = s + '%';
    }
);

then會傳遞錯誤,也就是說有多個任務序列執行時,我們可以只在最後一個then定義onRejected。只定義了onRejected的then等同於otherwise,也就是說 otherwise(onRejected) 是 then(undefined, onRejected) 的簡便寫法。

then會在try..catch..的包裹之下執行任務,所以任務的異常都會被when.js捕獲,當做失敗狀態處理,類似這樣:

try {
    ...
} catch (e) {
    deferred.reject(e);
}

在任務狀態改變之後再then,依然可以正常工作,後續任務會立刻執行。如果要在多個任務最後做cleanup工作,而不管之前的任務成功與否,可以用ensure方法。它只接受一個引數onFulfilledOrRejected,始終會執行。另外when.js還有一個always方法,即將廢棄,建議大家不要使用。

回到上面載入圖片的場景,如果把任務2變為:載入多張圖片,全部完成後再執行任務3。這時候需要用到when.all,when.all接受一個promise陣列,返回promise,這個promise會在promise陣列中每一個promise都resolve之後再resolve。說起來拗口,看程式碼就明白了(在瀏覽器中預覽):

var getData = function() {
    var deferred = when.defer();

    $.getJSON(api, function(data){
        var data = data.slice(0, 3);
        deferred.resolve(data);
    });

    return deferred.promise;
}

var getImg = function(src) {
    var deferred = when.defer();

    var img = new Image();

    img.onload = function() {
        deferred.resolve(img);
    };

    img.src = src;

    return deferred.promise;
}

var showImgs = function(imgs) {
    $(imgs).appendTo($('#container'));
}

var getImgs = function(data) {
    var deferreds = [];
    for(var i = 0; i < data.length; i++) {
        deferreds.push(getImg(data[i]));
    }
    return deferreds;
}

when.all(getData().then(getImgs)).then(showImgs);

如果我們只是想把一個promise陣列挨個執行一遍,可以用when.settle:

var promise1 = function() {
    var deferred = when.defer();
    setTimeout(function() {
            deferred.reject('A');
        }, 2000);
    return deferred.promise;
};

var promise2 = function() {
    var deferred = when.defer();
    setTimeout(function() {
            deferred.resolve('B');
        }, 2000);
    return deferred.promise;
};

when.settle([promise1(), promise2()]).then(function(result) {
    console.log(result); /*
    [{"state":"rejected","reason":"A"},
    {"state":"fulfilled","value":"B"}] */ 
});

有時候,我們需要引入任務競爭機制,例如從一批cdn中找到最快的那個,when.any就派上用場了,when.any接受promise陣列,在其中任何一個resolve後就接著執行後續任務了。如果要在一批promise中某幾個resolve後執行後續任務,可以用when.some,它比when.any多一個howMany的引數。

Promise給非同步程式設計程式碼帶來了巨大的方便,從此我們可以更專注單個任務的實現,promise會很好的替我們解決任務排程問題。when.js提供的功能遠遠不止本文提到的這些,有興趣的同學可以前往官方api文件瞭解更多。

--EOF--

提醒:本文最後更新於 2028 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

相關推薦

非同步程式設計When.js快速上手

提醒:本文最後更新於 2028 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 前些天我在團內做了一個關於AngularJS的分享。由於AngularJS大量使用Promise,所以我把基於Promise的非同步程式設計也一併介紹了下。很多東西都是一帶而過,這裡再記錄下。 AngularJS內建

一個例子讀懂 JS 非同步程式設計 Callback / Promise / Generator / Async

JS非同步程式設計實踐理解 回顧JS非同步程式設計方法的發展,主要有以下幾種方式: Callback Promise Generator Async 需求 顯示購物車商品列表的頁面,使用者可以勾選想要刪除商品(單選或多選),點選確認刪除按鈕後,將已勾選的商品清除購物車,頁面顯示剩餘商品。 為了便於本文內容

webpack-第02節讓你快速上手一個Demo

bpa live data- ati translate 輸入 理解 dex ans 上節課已經安裝好了Webpack到電腦上,這節課就開始一個簡單的Demo,讓你快速上手和熟悉Webpack的基本用法,學習並作完這節課內容你就可以和朋友小吹一下說:我也會Webpack。

Node.js學習筆記(1)Node.js快速開始

path 文本文 下載 啟動程序 直接 查看 學習筆記 完成後 編輯器 Node.js學習筆記(1):Node.js快速開始 Node.js的安裝 下載 官方網址:https://nodejs.org/en/ 說明:   在Windows上安裝時務必選擇全部組件,包括勾選

輕量級MVVM框架Vue.js快速上手(MVVM、SEO單頁面應用)

靈活 vue.js 課程 基礎 har rip 完成 crud 通過 輕量級MVVM框架Vue.js快速上手(MVVM、SEO單頁面應用、×××服務器端渲染、Nuxt.js) 網盤地址:https://pan.baidu.com/s/1LkhepNpGAtRjrxp_CVJ

Reveal.js 快速上手

簡介 本文介紹 Reveal.js (原始碼) 的基本概念和日常使用命令/方式/工作流。 這一工具可以製作出很好的展示 PPT,能充分利用 web 技術,不過筆者這裡只將其作為一個快速製作可展示的單 html 檔案的工具。 來自參考資料 6 的圖瞭解一下效果: 環境

【譯】非同步程式設計Futures

關鍵點 dart是單執行緒語言 同步程式碼會阻塞你的程式 使用Future物件來執行非同步操作 在async函式裡使用await關鍵字來掛起執行知道一個Future操作完成 或者使用then()方法 在async函式裡使用try-catch表示式捕獲錯誤 或者

ArcGIS API for JavaScript 實戰與解析(一)簡介與快速上手

在這篇文章之前廢話幾句。 自從過完十一假期,每天都在奔波和加班中度過,直到今天才真正能夠休息。隱約記得去年是同樣的情形,但並不是相同的事由,希望明年十月對我好一點。 從二月到十月的八個月裡,我幾乎每天都堅持學習,從程式語言、軟體開發到機器學習、WebGIS,還有

Vue.js快速上手|單向繫結與雙向繫結

 概述 Vue.js 最顯著的特點就是響應式和資料驅動,也就是將Model和View進行單向繫結或者雙向繫結。單向繫結:把Model繫結到View,當我們用JavaScript程式碼更新Model時,View就會自動更新。因此,我們不需要進行額外的DOM操作,只需要進行Mod

Python 中的非同步程式設計Asyncio

如果你已經決定要理解 Python 的非同步部分,歡迎來到我們的“Asyncio How-to ”。 注:哪怕連異動正規化的存在都不知道的情況下,你也可以成功地使用 Python。但是,如果你對底層執行模式感興趣的話,asyncio 絕對值得檢視。 非同步是怎麼一回事? 在傳統

分享《Python程式設計快速上手讓繁瑣工作自動化》【高清中文版PDF+高清英文版PDF+原始碼】

下載:https://pan.baidu.com/s/1qs1ETO6yTG8xpdPPzb5dPw Python程式設計快速上手:讓繁瑣工作自動化【高清中文版PDF+高清英文版PDF+原始碼】 久負盛名的python書籍。 高清中文版412頁,高清英文版505 頁,配套原始碼。 中文和英文兩版對比學

每日練習三《Python程式設計快速上手+讓繁瑣工作自動化》第五章實踐專案

假設征服一條龍的戰利品表示為這樣的字串列表:dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']寫一個名為 addToInventory(inventory, addedItems)的函式,其中 inventory 引數是

翻譯使用Libevent的快速可移植非阻塞網路程式設計非同步IO簡介 (一) (轉)

/* For sockaddr_in */#include <netinet/in.h>/* For socket functions */#include <sys/socket.h>/* For fcntl */#include <fcntl.h>#include &l

《Python程式設計快速上手》實踐專案瘋狂填詞

一.專案要求:建立一個瘋狂填詞(Mad Libs)程式,它將讀入文字檔案, 並讓使用者在該文字檔案中出現 ADJECTIVE、 NOUN、 ADVERB 或 VERB 等單詞的地方, 加上他們自己的文字。例如,一個文字檔案可能看起來像這樣:The ADJECTIVE pand

(轉)Django學習之 第二章Django快速上手

nbsp ida IT 介紹 你在 django edi nal python代碼 安裝Python 安裝Django非常容易。因為Django可以運行在任何可以運行Python的環境中,所以可以以多種方式進行配置。 在本章我們將嘗試覆蓋幾種常見的Django安裝場景。

快速上手在CVM上安裝Apache

tp服務器 以及 部署 地址欄 騰訊雲 smo ive ubun 一個 歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐幹貨哦~ 本文由一步 發表於雲+社區專欄 介紹 Apache HTTP服務器是世界上使用最廣泛的Web服務器。它提供了許多強大的功能,包括可動態加載

spring-data詳解之spring-data-jpa簡單三步快速上手spring-data-jpa開發

事務管理 out don 前言 map lns xid public lease 前言: 基於spring framework 4.x或spring boot 1.x開發環境 務必註意以下版本問題:Spring framework4.x(Spring boot1.x)對應s

分享《Python編程快速上手讓繁瑣工作自動化》【高清中文版PDF+高清英文版PDF+源代碼】

其中 mage pytho oss 英文 復制粘貼 學習 color process 下載:https://pan.baidu.com/s/1qs1ETO6yTG8xpdPPzb5dPw Python編程快速上手:讓繁瑣工作自動化【高清中文版PDF+高清英文版PDF+源代碼

《Python編程快速上手讓繁瑣工作自動化》【高清中文版PDF+高清英文版PDF+源代碼】

text cto 講解 proc mark 書籍 blog shadow 分享圖片 下載:https://pan.baidu.com/s/1qs1ETO6yTG8xpdPPzb5dPw Python編程快速上手:讓繁瑣工作自動化【高清中文版PDF+高清英文版PDF+源代碼】

分享《Python 遊戲程式設計快速上手(第3版)》高清中文版PDF+高清英文版PDF+原始碼

下載:https://pan.baidu.com/s/1n4hyQq1YFkuLiL2G3388fw 更多資料分享:http://blog.51cto.com/3215120 《Python 遊戲程式設計快速上手(第3版)》高清中文版PDF+高清英文版PDF+原始碼高清中文版,帶目錄和書籤,文字能夠複製貼