angular中的異步編程 $q的使用

前言:

我們知道,JavaScript語言的執行環境是單線程的。


所謂"單線程",就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執行後面一個任務,以此類推。

這種模式的好處是實現起來比較簡單,執行環境相對單純;壞處是只要有一個任務耗時很長,後面的任務都必須排隊等着,會拖延整個程序的執行。常見的瀏覽器無響應(假死),往往就是因爲某一段Javascript代碼長時間運行(比如死循環),導致整個頁面卡在這個地方,其他任務無法執行。
爲了解決這個問題,Javascript語言將任務的執行模式分成兩種:同步(Synchronous)和異步(Asynchronous)。
"同步模式"就是上一段的模式,後一個任務等待前一個任務結束,然後再執行,程序的執行順序與任務的排列順序是一致的、同步的;
"異步模式"則完全不同,每一個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,所以程序的執行順序與任務的排列順序是不一致的、異步的。
通常,我們執行異步的方法是通過回調函數,如:
function f1(){
    setTimeout(function () {
        //doSomething
        setTimeout(function () {
            //doSomething
            setTimeout(function () {
                //doSomething
            },300)
        },200)
    },100)
}
這樣書寫固然簡單,但是問題也來了,金字塔類型的接口不利於代碼閱讀與維護,如果,代碼寫成這樣,會不會更利於閱讀維護呢?
f1
    .then(function () {

    })
    .then(function () {

    })
    .then(function () {

    });
即將原來的回調金字塔式改寫成鏈式,這樣我們就可以很清楚的看清楚每個方法執行的是什麼了。

因此CommonJS提出一種Promise規範,目的是爲了異步編程提供統一的接口

Jquery中的promise

在jquery1.5版本後,引入了promise對象,實現了基本的promise,如果你在jquery1.5以上版本,可以發現 原來的ajax方法還可以這樣用
var jqxhr = $.ajax( "example.php" )
    .done(function() {
        alert( "success" );
    })
    .fail(function() {
        alert( "error" );
    })
    .always(function() {
        alert( "complete" );
    });

將原來嵌入內部的success,error方法變爲鏈式調用,這是因爲在1.5版本,ajax方法進行了封裝,$.ajax()獲得的是一個$.Deferred對象。
因此,我們可以知道Deferred對象可以完成鏈式異步調用,

因此,我們可以將這樣的形式
function wait(resolve){
    var a=1;
    resolve(a);
}

wait(function (data) {
    alert(data)
});
改寫成
 function wait() {
        var def = $.Deferred();           //獲取deferred對象
        def.resolve(1); // 改變Deferred對象的執行狀態    ,resolve爲成功狀態 //當收到resolve時,變執行then方法
        setTimeout(tasks, 1000);
        return def.promise();
    }

    $.when(wait())
            .then(function (data) {
                alert(data);   //1  該值有resolve(1) 中的1得來
            })

時候,我們需要不止一部,可能需要多個步驟,那麼只需要 在前一個then的回調中籤返回值就可,從這裏我們能夠看出 .then()方法返回的也是一個deferred.promise對象
    $.when(wait())
            .then(function (data) {
                alert(data);
                return data+1;
            })
            .then(function (data) {
                alert(data);
            });

angular中的promise

同上,在angular中,我們也支持promise異步方法,他使用了一個內置對象$q
具體使用代碼如下:
<span style="white-space:pre">	</span>var getData = function () {
            var defer = $q.defer();       //同jquery $.Deferred
            $timeout(function () {
                defer.resolve(1);         //改變成功狀態
            }, 1000);

            return defer.promise;
        };
        getData()
                .then(function (data) {       //getData執行完成後
                    alert(data);                  //1
                    return data+1;             
                })
                .then(function (data) {
                   alert(data);                    //2
                });
注意,angular還有一個when方法,他和jquery中的$.when()還是有一些區別的,如下

<span style="font-family:Microsoft YaHei;">var def = $q.defer();
        var q=$q.when(12);
        q.then(function (data) {
            alert(data); //12
        });</span>
angular 中$q.when()方法是將裏面的參數封裝成一個$q.defer().promise對象,因此 可以通過then方法獲取when裏面的值
而Jquery中,$.when()接收的是一個deferred對象,不滿足promise/A規範。

總結

其實在promise/A規範中還有很多關於promise的定義,如all() 、spread() 、race() 、denodeify() ,如果想了解 promise 的更多功能,我建議諸位看看 Bluebird 函數庫的 API。本文只記錄了最簡單的形式,如果有什麼問題,望指正,謝謝。

推薦閱讀 






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章