關於Promise

掘金上看見一篇寫promise的文章,感受做者寫的很棒,文章連接在這:八段代碼完全掌握 Promise 。看完以後感受學到了不少,因此又從新把JavaScript Promise迷你書(中文版)刷了一遍,如下是我對於promise的理解。es6

Promise 是什麼?

所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。 —— ECMAScript 6 入門 阮一峯api

Promise對象表明一個異步操做,有三種狀態:Pending(準備狀態),Fulfilled(成功狀態,也稱爲Resolved狀態),Rejected(失敗狀態)。只有異步操做的結果能夠決定promise對象的狀態,操做成功後,promise對象由Pending狀態轉換爲Fulfilled狀態,此時回調函數會執行 onFulfilled方法。反之,操做失敗,promise對象由pending狀態轉換爲Rejected狀態,此時回調函數會執行onRejected方法。
以下圖所示:數組

Promise狀態改變

建立一個Promise對象
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 的基本API

1.Promise#then

Promise.then(onFulfilled,onRejected)函數

then方法定義了promise狀態變爲resolved或者rejected狀態以後的回調函數:post

  • pending->resolved:執行onFulfilled函數,而且將promise對象的值傳給onFulfilled函數
  • pending->rejected:執行onRejected函數,而且將promise對象的值傳給onRejected函數

代碼示例以下: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"以前輸出。對象

2.Promise#catch

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能夠捕獲到。

catch異常捕獲

3.Promise.resolve

這個方法會根據傳進來的參數的不一樣,返回不一樣的promise對象。

//1.傳入的參數是一個普通值
var p1 = Promise.resolve(1);//返回一個將該對象做爲值的新promise對象
//2.傳入的參數是一個Promise對象
var p2 = Promise.resolve(p1);//返回接收到的promise對象

p1 === p2   //true

在迷你書中介紹了三種狀況,除了上面兩種以外,還有一種thenable類型的對象的時候,那種這裏就不作介紹了,有興趣的朋友能夠本身去看看啊~

4.Promise.reject

這個方法跟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對象。

5.Promise.all

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]
});
6.Promise.race

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

Promise Demo

這是個很大的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);
  }
);

p_1,p_2,p_3,p_4的值

採用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的值

兩種方式定義的p1,p2,p3,p4都是相同的,從這段代碼能夠看出,不管是用那種方式建立promise對象,若是使用Promise.resolve方法傳入一個新對象,仍是會去‘讀取’(可理解爲)這個對象的,可是Promise.reject方法傳入一個新對象,並不會去‘讀取’這個對象,而會直接返回這個這個對象。(這個‘讀取’的概念並非promise中的概念,只是個人我的理解,在八段代碼完全掌握 Promise 這篇文章中,做者把他解釋爲‘拆箱’,也是做者的一種讓人理解起來更簡單的思路,至於promise官方文檔中的規定,目前尚未去仔細深刻研究,有時間會去看一下^-^)

new方式 回調執行結果

api方式 回調執行結果

從這段代碼能夠看出,兩種方式的執行順序會有差異,至於爲何,今天也查找了不少資料,可是並無找到緣由,有研究過的大神歡迎指導~~

相關文章
相關標籤/搜索