ES6 Promise

問題

JavaScript的Callback機制深入人心。而ECMAScript的世界同樣充斥的各種異步操作(異步IO、setTimeout等)。異步和Callback的搭載很容易就衍生"回調金字塔"。——由此產生Deferred/Promise。

Deferred起源于Python,后來被CommonJS挖掘并發揚光大,得到了大名鼎鼎的Promise,并且已經納入ECMAScript 6(JavaScript下一版本)。

Promise/Deferred是當今最著名的異步模型,不僅強壯了JavaScript Event Loop(事件輪詢)機制下異步代碼的模型,同時增強了異步代碼的可靠性。

有了 Promise ,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise 對象提供統一的接口,使得控制異步操作更加容易。

概述

Promise 對象用于延遲(deferred) 計算和異步(asynchronous ) 計算。一個Promise對象代表著一個還未完成,但預期將來會完成的操作。

語法

    new Promise(executor);
    new Promise(function(resolve, reject) { ... });

例子:
<pre>
var promise = new Promise(function(resolve, reject) {
if (/** 異步操作成功* */){
resolve(value);
} else {
reject(error);
}
});
</br>
promise.then(function(value) {
// success
},
function(value) {
// failure
});
</pre>

參數

executor帶有 resolvereject 兩個參數的函數對象。一旦我們的操作完成即可調用這些函數。

  • 第一個參數用在處理執行成功的場景
  • 第二個參數則用在處理執行失敗的場景。

描述

Promise對象是一個返回值的代理,這個返回值在promise對象創建時未必已知。它允許你為異步操作的成功或失敗指定處理方法。 這使得異步方法可以像同步方法那樣返回值:異步方法會返回一個包含了原返回值的 promise 對象來替代原返回值。

Promise對象有以下幾種狀態:

  • pending: 初始狀態, 非 fulfilled 或 rejected.
  • fulfilled: 成功的操作.
  • rejected: 失敗的操作.

pending狀態的promise對象既可轉換為帶著一個成功值的fulfilled 狀態,也可變為帶著一個失敗信息的 rejected 狀態。

特點

  • 對象的狀態不受外界影響,只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
    當狀態發生轉換時,promise.then綁定的方法(函數句柄)就會被調用。

  • 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

當綁定方法時,如果 promise對象已經處于 fulfilled 或 rejected 狀態,那么相應的方法將會被立刻調用, 所以在異步操作的完成情況和它的綁定方法之間不存在競爭條件。
因為Promise.prototype.then
Promise.prototype.catch

方法返回 promises對象, 所以它們可以被鏈式調用—— 一種被稱為 composition 的操作。


注意: 如果一個promise對象處在fulfilled或rejected狀態而不是pending狀態,那么它也可以被稱為
settled
狀態。你可能也會聽到一個術語resolved ,它表示promise對象處于settled狀態,或者promise對象被鎖定在了調用鏈中。關于promise的狀態, Domenic Denicola 的 States and fates 有更多詳情可供參考。

基本的api

  • Promise.resolve()
  • Promise.reject()
  • Promise.prototype.then()
  • Promise.prototype.catch()
  • Promise.all() 完成全部
  • Promise.race() 完成一個

常用的JavaScript的promise的寫法

<pre>
function get(uri){
return http(uri, 'GET', null);
}

</br>

function post(uri,data){
if(typeof data === 'object' && !(data instanceof String || (FormData && data instanceof FormData))) {
var params = [];
for(var p in data) {
if(data[p] instanceof Array) {
for(var i = 0; i < data[p].length; i++) {
params.push(encodeURIComponent(p) + '[]=' + encodeURIComponent(data[p][i]));
}
} else {
params.push(encodeURIComponent(p) + '=' + encodeURIComponent(data[p]));
}
}
data = params.join('&');
}

return http(uri, 'POST', data || null, {
    "Content-type":"application/x-www-form-urlencoded"
});

}
</br>

function http(uri,method,data,headers){
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method,uri,true);
if(headers) {
for(var p in headers) {
xhr.setRequestHeader(p, headers[p]);
}
}
xhr.addEventListener('readystatechange',function(e){
if(xhr.readyState === 4) {
if(String(xhr.status).match(/^2\d\d$/)) {
resolve(xhr.responseText);
} else {
reject(xhr);
}
}
});
xhr.send(data);
})
}

</br>

function wait(duration){
return new Promise(function(resolve, reject) {
setTimeout(resolve,duration);
})
}

</br>

function waitFor(element,event,useCapture){
return new Promise(function(resolve, reject) {
element.addEventListener(event,function listener(event){
resolve(event)
this.removeEventListener(event, listener, useCapture);
},useCapture)
})
}

</br>

function loadImage(src) {
return new Promise(function(resolve, reject) {
var image = new Image;
image.addEventListener('load',function listener() {
resolve(image);
this.removeEventListener('load', listener, useCapture);
});
image.src = src;
image.addEventListener('error',reject);
})
}

</br>

function runScript(src) {
return new Promise(function(resolve, reject) {
var script = document.createElement('script');
script.src = src;
script.addEventListener('load',resolve);
script.addEventListener('error',reject);
(document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script);
})
}

</br>

function domReady() {
return new Promise(function(resolve, reject) {
if(document.readyState === 'complete') {
resolve();
} else {
document.addEventListener('DOMContentLoaded',resolve);
}
})
}
</pre>

兼容性墊片polyfill of the ES6 Promise

es6-promise
es6-promise

參考資料:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容

  • Promise的含義: ??Promise是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和...
    呼呼哥閱讀 2,185評論 0 16
  • 前言 在Promise之前,js的異步編程都是采用回調函數和事件的方式。但是這種編程方式在處理復雜業務的情況下,很...
    卓三陽閱讀 845評論 0 1
  • 如果瀏覽已經有了Promise對象,那么頁就說明瀏覽器的js引擎里已經有了Promsise隊列,這樣就可以利用Pr...
    羊烊羴閱讀 516評論 0 0
  • ES6-Promise對象 (上) 1.Promise對象方法 (1)Promise.all(iterable);...
    卓三陽閱讀 349評論 0 1
  • Promiese 簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果,語法上說,Pr...
    雨飛飛雨閱讀 3,367評論 0 19