Promise 學習筆記 - 時間支配者


本文同步自我的個人博客:http://www.52cik.com/2015/11/08/promise.html

JavaScript 的 promises 事實標准稱為 Promises/A+。ES6 的 Promise API 便遵循這個標准。
promises 的英文直譯是“承諾,諾言”。但是在張鑫旭大神的《ES6 JavaScript Promise的感性認知》文章里得知,
而是應該根據其音譯——“普羅米修斯”,來翻譯。普羅米修斯是希臘神話故事中的英雄,名字的意思是“先知”。

回調地獄

好了,我就不講那些學術化的東西了,直接進入正題,來個實際的例子比什么都強。
例如我們有3個 ajax 請求,需要按照順序加載。

$.get("/url1", function (data) {
    // 一些處理
    $.get("/url2", function (data) {
        // 一些處理
        $.get("/url3", function (data) {
            // 最終處理
        });
    });
});

非常熟悉的畫面,那如果請求增加到10個,甚至更多,會發生什么呢?

The callback hell!

這幅圖非常直觀形象的展示了回調地獄。

時間支配 - 按順序調度

為了避免回調地獄的發生,就需要 Promise 出馬來合理的支配我們的任務時間。
首先需要學習下第一個 api,具體參閱 MDN Promise 文檔。
其實非常簡單,就是用 Promise 包裝下 ajax 請求即可,代碼如下。

// 用 Promise 包裝 get 請求
function myGet(url) {
    return new Promise(function(resolve, reject) {
        $.get(url, resolve);
    });
}

myGet('/url1').then(function (data) {
    // 一些處理,data為返回值
    return myGet('/url2');
}).then(function (data) {
    // 一些處理
    return myGet('/url3');
}).then(function (data) {
    // 最終處理
});

這樣就可以按順序寫 ajax 調用了,不會陷入無盡的回調之中。
如果你熟悉 jquery,那么你一定知道 Deferred,它實現了類似 Promise 的東西。

$.get("/url1").then(function (data) {
    // 一些處理,data為返回值
    return $.get("/url2");
}).then(function (data) {
    // 一些處理
    return $.get("/url3");
}).then(function (data) {
    // 最終處理
});

這樣看着簡潔多了,雖然 Deferred 和 Promise 實現方法不一樣,但是他們的結果是一致的。

時間支配 - 異步並發

大家都知道 ajax 異步請求是沒有返回順序的,發了3個請求,有可能是1,2,3的返回,也有可能是3,1,2的返回順序。
那我不想按順序請求,而是並發請求,但是在最終所有請求完成后執行一段操作。
比如頁面所有數據都加載完后隱藏 loading 層。

這個時候,需要用到一個新方法 Promise.all,其實很簡單,它接受一個 promise 數組最為參數。

function myGet(url) {
    return new Promise(function(resolve, reject) {
        $.get(url, resolve);
    });
}

var arr = [];
arr.push(myGet('/url1'));
arr.push(myGet('/url2'));
arr.push(myGet('/url3'));

Promise.all(arr).then(function (datas) {
    // 最終處理,datas 是所有返回結果的數組
    console.log("返回數據為", datas);
});

感覺比剛才的按順序還要清爽,有木有。其實 jquery 也有類似的功能,而且用起來超爽的。

$.when($.get('/url1'), $.get('/url2'), $.get('/url3'))
.then(function (data1, data2, data3) {
    // 最終處理
    console.log("返回數據為", data1, data2, data3);
});

雖然形式有點怪異,不過調整下就OK了。

var arr = [];
arr.push($.get('/url1'));
arr.push($.get('/url2'));
arr.push($.get('/url3'));

$.when.apply(null, arr).then(function () {
    // 最終處理
    console.log("返回數據為", arguments);
});

利用 apply 來展開參數,代碼看着舒服多了,跟上面的 Promise.all 是一樣一樣的。

結束語

本文本是我在一邊學習測試一邊寫的,例子都跑過OK的,通篇下來后,對 Deferred 和 Promise 有了一定認識,
雖然並不一定透徹,至少比起以前好多了。

為什么叫它為 時間支配者 呢,一開始沒這樣的想法,寫到一半的時候發現確實可以合理的支配異步的時間調度問題。
異步操作最大的特點就是時間的不確定性,所以正常情況下很難流暢的書寫簡單而有邏輯性的代碼。

比如按順序的異步,雖然可以合理的回調,但是會陷入回調地獄,再如並發異步呢?
並發異步,也許你要設置一個全局變量來記次,最后一個完成的,要觸發下完成后的任務。
這樣雖然也可以實現,但是代碼會顯的臃腫而又凌亂。

但是有了 Promise 的幫助,這一切變的這么簡單,自然。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM