在 掘金上看見一篇寫promise的文章,感受做者寫的很棒,文章連接在這:八段代碼完全掌握 Promise 。看完以後感受學到了不少,因此又從新把JavaScript Promise迷你書(中文版)刷了一遍,如下是我對於promise的理解。es6
所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。 —— ECMAScript 6 入門 阮一峯api
Promise對象表明一個異步操做,有三種狀態:Pending(準備狀態),Fulfilled(成功狀態,也稱爲Resolved狀態),Rejected(失敗狀態)。只有異步操做的結果能夠決定promise對象的狀態,操做成功後,promise對象由Pending狀態轉換爲Fulfilled狀態,此時回調函數會執行 onFulfilled方法。反之,操做失敗,promise對象由pending狀態轉換爲Rejected狀態,此時回調函數會執行onRejected方法。
以下圖所示:數組
var p1 = new Promise(function(resolve,reject){ resolve('resolve'); }); var p2 = new Promise(function(resolve,reject){ reject('reject'); });
p1 返回一個resolved狀態,值爲resolve的Promise對象promise
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "resolve"}
p2 返回一個rejected狀態,值爲reject的Promise對象異步
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: "reject"}
Promise.then(onFulfilled,onRejected)函數
then方法定義了promise狀態變爲resolved或者rejected狀態以後的回調函數:post
代碼示例以下:spa
var p = new Promise(function(resolve, reject){ console.log("create a promise"); resolve("success"); }); console.log("after new Promise"); p.then(function onFulfilled(value){ console.log(value); },function onRejected(error){ console.log(error); });
運行結果以下:code
"create a promise" "after new Promise" "success"
new Promise返回一個resolved狀態的promise對象,因此在p.then()方法中調用的是onFulfilled函數。
建立promise時,promise對象中的函數是當即執行的,並非在調用then方法的時候纔會去執行,因此首先會輸出"create a promise"。可是執行的代碼是異步代碼,因此"after new Promise"會在"success"以前輸出。對象
promise.catch(onRejected);
catch方法捕獲了promise運行過程當中的異常。catch與then方法中的onRejected的不一樣是,onRejected 函數只能在promise狀態變爲rejected的時候調用,但catch既能夠在promise狀態變爲rejected的時候調用,又能夠捕獲第一個onFulfilled方法中出現的錯誤。
能夠參考promise迷你書中的這一段代碼:
function throwError(value) { // 拋出異常 throw new Error(value); } // <1> onRejected不會被調用 function badMain(onRejected) { return Promise.resolve(42).then(throwError, onRejected); } // <2> 有異常發生時onRejected會被調用 function goodMain(onRejected) { return Promise.resolve(42).then(throwError).catch(onRejected); } // 運行示例 badMain(function(){ console.log("BAD"); }); goodMain(function(){ console.log("GOOD"); });
在這段代碼中,badMain函數中傳入onRejected參數,由於Promise.resolve(42)返回一個resolved狀態的promise對象(這個api的用法會在下一節中說到),因此會去調用throwError函數,throwError函數中拋出的異常onRejected是捕獲不到的,可是catch能夠捕獲到。
這個方法會根據傳進來的參數的不一樣,返回不一樣的promise對象。
//1.傳入的參數是一個普通值 var p1 = Promise.resolve(1);//返回一個將該對象做爲值的新promise對象 //2.傳入的參數是一個Promise對象 var p2 = Promise.resolve(p1);//返回接收到的promise對象 p1 === p2 //true
在迷你書中介紹了三種狀況,除了上面兩種以外,還有一種thenable類型的對象的時候,那種這裏就不作介紹了,有興趣的朋友能夠本身去看看啊~
這個方法跟Promise.resolve方法同樣,會根據傳進來的參數的不一樣,返回不一樣的promise對象。
//1.傳入的參數是一個普通值 var p3 = Promise.reject(1);//返回一個將該對象做爲值的新promise對象 //2.傳入的參數是一個Promise對象 var p4 = Promise.reject(p3);//返回一個新的promise對象 p3 === p4 //false
跟resolve不一樣的是,當傳入的參數是一個Promise對象的時候,會返回一個rejected狀態的新promise對象。
Promise.all接收一個 promise對象的數組做爲參數,當這個數組裏的全部promise對象所有變爲resolve或reject狀態的時候,它纔會去調用 .then 方法。
示例代碼:
var p1 = Promise.resolve(1), p2 = Promise.resolve(2), p3 = Promise.resolve(3); Promise.all([p1, p2, p3]).then(function (results) { console.log(results); // [1, 2, 3] });
Promise.race也是接收一個 promise對象的數組做爲參數,參數 promise 數組中的任何一個promise對象若是變爲resolve或者reject的話, 該函數就會返回,並使用這個promise對象的值進行resolve或者reject。
var p1 = Promise.resolve(1), p2 = Promise.resolve(2), p3 = Promise.resolve(3); Promise.race([p1, p2, p3]).then(function (value) { console.log(value); // 1 });
這裏須要注意的是,雖然在p1resolved以後便執行了then方法,可是並非意味着日後的promise對象不執行了,其餘的仍是promise對象仍是要執行的,只是不會再調用then函數。
下面這個demo即可以看出:
var p1 = new Promise(function(resolve,reject){ console.log('I am p1!'); resolve(1); }); var p2 = new Promise(function(resolve,reject){ console.log('I am p2!'); resolve(2); }); var p3 = new Promise(function(resolve,reject){ console.log('I am p3!'); resolve(3); }); Promise.race([p1, p2, p3]).then(function (value) { console.log(value); });
運行結果:
I am p1! I am p2! I am p3! 1
這是個很大的demo,,^-^, 涵蓋了不少小知識點,
var p_1 = new Promise(function(resolve,reject){ resolve(1); }); var p_2 = Promise.resolve(1); var p_3 = Promise.reject(1); var p_4 = Promise.resolve(p_2); // 方式1 var p1 = new Promise(function(resolve, reject){ resolve(Promise.resolve('resolve')); }); var p2 = new Promise(function(resolve, reject){ resolve(Promise.reject('reject')); }); var p3 = new Promise(function(resolve, reject){ reject(Promise.resolve('resolve')); }); var p4 = new Promise(function(resolve, reject){ reject(Promise.reject('reject')); }); //方式2 var p1 = Promise.resolve(Promise.resolve('resolve')) var p2 = Promise.resolve(Promise.reject('reject')) var p3 = Promise.reject(Promise.resolve('resolve')) var p4 = Promise.reject(Promise.reject('reject')) //定義回調函數 p1.then( function fulfilled(value){ console.log('fulfilled1: ' + value); }, function rejected(err){ console.log('rejected1: ' + err); } ); p2.then( function fulfilled(value){ console.log('fulfilled2: ' + value); }, function rejected(err){ console.log('rejected2: ' + err); } ); p3.then( function fulfilled(value){ console.log('fulfilled3: ' + value); }, function rejected(err){ console.log('rejected3: ' + err); } ); p4.then( function fulfilled(value){ console.log('fulfilled4: ' + value); }, function rejected(err){ console.log('rejected4: ' + err); } );
採用new Promise 方式建立對象和採用Promise.resolve方法建立出來的對象實際上是同樣的,能夠把Promise.resolve看作new Promise 的語法糖。只不過須要注意的是,在上面介紹resolve方法的時候說過,若是傳入的參數是一個promise對象,會直接返回這個對象,,因此p_2===p_4
輸出的是true,可是經過new的方式建立出來的對象都是新建立的,因此new出來的對象跟別的對象都不會全等,即p_1===p_2
會輸出false。
兩種方式定義的p1,p2,p3,p4都是相同的,從這段代碼能夠看出,不管是用那種方式建立promise對象,若是使用Promise.resolve方法傳入一個新對象,仍是會去‘讀取’(可理解爲)這個對象的,可是Promise.reject方法傳入一個新對象,並不會去‘讀取’這個對象,而會直接返回這個這個對象。(這個‘讀取’的概念並非promise中的概念,只是個人我的理解,在八段代碼完全掌握 Promise 這篇文章中,做者把他解釋爲‘拆箱’,也是做者的一種讓人理解起來更簡單的思路,至於promise官方文檔中的規定,目前尚未去仔細深刻研究,有時間會去看一下^-^)
從這段代碼能夠看出,兩種方式的執行順序會有差異,至於爲何,今天也查找了不少資料,可是並無找到緣由,有研究過的大神歡迎指導~~