Promise特性及用法

Skyshine發表於2020-01-20

定義

ES6 原生提供了 Promise 物件。

所謂 Promise,就是一個物件,用來傳遞非同步操作的訊息。它代表了某個未來才會知道結果的事件(通常是一個非同步操作),並且這個事件提供統一的 API,可供進一步處理。 Promise是非同步程式設計的一種解決方案

基本API

基本的 api

Promise.resolve()

Promise.reject()

Promise.prototype.then()

Promise.prototype.catch()

Promise.all() // 所有的完成

var p = Promise.all([p1,p2,p3]);

Promise.race() // 競速,完成一個即可

三種狀態

Promise的內部實現是一個狀態機。 Promise有三種狀態:pending,resolved,rejected。 當Promise剛建立完成時,處於pending狀態; 當Promise中的函式引數執行了resolve後,Promise由pending狀態變成resolved狀態; 如果在Promise的函式引數中執行的不是resolve方法,而是reject方法,那麼Promise會由pending狀態變成rejected狀態。

用法與特性

1、程式碼立即執行

var p = new Promise(function(resolve, reject){
  console.log("create a promise");
  resolve("success");
});

console.log("after new Promise");

p.then(function(value){
  console.log(value);
});
複製程式碼

輸出結果

1、"create a promise"

2、"after new Promise"

3、"success"

2、狀態的不可逆性

var p1 = new Promise(function(resolve, reject){
  resolve("success1");
  resolve("success2");
});

var p2 = new Promise(function(resolve, reject){
  resolve("success");
  reject("reject");
});

p1.then(function(value){
  console.log(value);
});

p2.then(function(value){
  console.log(value);
});
複製程式碼

Promise狀態的一旦變成resolved或rejected時,Promise的狀態和值就固定下來了,不論你後續再怎麼呼叫resolve或reject方法,都不能改變它的狀態和值。

3、回撥非同步性

var p = new Promise(function(resolve, reject){
  resolve("success");
});

p.then(function(value){
  console.log(value);
});

console.log("which one is called first ?");
複製程式碼

4、鏈式呼叫

var p = new Promise(function(resolve, reject){
  resolve(1);
});
p.then(function(value){               //第一個then
  console.log(value);
  return value*2;
}).then(function(value){              //第二個then
  console.log(value);
}).then(function(value){              //第三個then
  console.log(value);
  return Promise.resolve('resolve'); 
}).then(function(value){              //第四個then
  console.log(value);
  return Promise.reject('reject');
}).then(function(value){              //第五個then
  console.log('resolve: '+ value);
}, function(err){
  console.log('reject: ' + err);
})
複製程式碼

結果輸出

1

2

undefined

"resolve"

"reject: reject"

Promise物件的then方法返回一個新的Promise物件,因此可以通過鏈式呼叫then方法。then方法接收兩個函式作為引數,第一個引數是Promise執行成功時的回撥,第二個引數是Promise執行失敗時的回撥。兩個函式只會有一個被呼叫,函式的返回值將被用作建立then返回的Promise物件。這兩個引數的返回值可以是以下三種情況中的一種:

return 一個同步的值 ,或者 undefined(當沒有返回一個有效值時,預設返回undefined),then方法將返回一個resolved狀態的Promise物件,Promise物件的值就是這個返回值。 return 另一個 Promise,then方法將根據這個Promise的狀態和值建立一個新的Promise物件返回。 throw 一個同步異常,then方法將返回一個rejected狀態的Promise, 值是該異常。

異常

var p1 = new Promise( function(resolve,reject){
  foo.bar();
  resolve( 1 );	  
});

p1.then(
  function(value){
    console.log('p1 then value: ' + value);
  },
  function(err){
    console.log('p1 then err: ' + err);
  }
).then(
  function(value){
    console.log('p1 then then value: '+value);
  },
  function(err){
    console.log('p1 then then err: ' + err);
  }
);
複製程式碼
var p2 = new Promise(function(resolve,reject){
  resolve( 2 );	
});

p2.then(
  function(value){
    console.log('p2 then value: ' + value);
    foo.bar();
  }, 
  function(err){
    console.log('p2 then err: ' + err);
  }
).then(
  function(value){
    console.log('p2 then then value: ' + value);
  },
  function(err){
    console.log('p2 then then err: ' + err);
    return 1;
  }
).then(
  function(value){
    console.log('p2 then then then value: ' + value);
  },
  function(err){
    console.log('p2 then then then err: ' + err);
  }
);
複製程式碼

p1 then err: ReferenceError: foo is not defined

p2 then value: 2

p1 then then value: undefined

p2 then then err: ReferenceError: foo is not defined

p2 then then then value: 1 Promise中的異常由then引數中第二個回撥函式(Promise執行失敗的回撥)處理,異常資訊將作為Promise的值。異常一旦得到處理,then返回的後續Promise物件將恢復正常,並會被Promise執行成功的回撥函式處理。另外,需要注意p1、p2 多級then的回撥函式是交替執行的 ,這正是由Promise then回撥的非同步性決定的。

then()方法使Promise原型鏈上的方法,它包含兩個引數方法,分別是已成功resolved的回撥和已失敗rejected的回撥

.catch()的作用是捕獲Promise的錯誤,與then()的rejected回撥作用幾乎一致。但是由於Promise的拋錯具有冒泡性質,能夠不斷傳遞,這樣就能夠在下一個catch()中統一處理這些錯誤。同時catch()也能夠捕獲then()中丟擲的錯誤,所以建議不要使用then()的rejected回撥,而是統一使用catch()來處理錯誤

同樣,catch()中也可以丟擲錯誤,由於丟擲的錯誤會在下一個catch中被捕獲處理,因此可以再新增catch()

使用rejects()方法改變狀態和丟擲錯誤 throw new Error() 的作用是相同的

當狀態已經改變為resolved後,即使丟擲錯誤,也不會觸發then()的錯誤回撥或者catch()方法

then() 和 catch() 都會返回一個新的Promise物件,可以鏈式呼叫

Promise.resolve() / Promise.reject()

用來包裝一個現有物件,將其轉變為Promise物件,但Promise.resolve()會根據引數情況返回不同的Promise:

引數是Promise:原樣返回 引數帶有then方法:轉換為Promise後立即執行then方法 引數不帶then方法、不是物件或沒有引數:返回resolved狀態的Promise

Promise.reject()會直接返回rejected狀態的Promise

Promise.all()

引數為Promise物件陣列,如果有不是Promise的物件,將會先通過上面的Promise.resolve()方法轉換

var promise = Promise.all( [p1, p2, p3] )
promise.then(
    ...
).catch(
    ...
)
複製程式碼

當p1、p2、p3的狀態都變成resolved時,promise才會變成resolved,並呼叫then()的已完成回撥,但只要有一個變成rejected狀態,promise就會立刻變成rejected狀態

Promise.race()

var promise = Promise.race( [p1, p2, p3] )
promise.then(
    ...
).catch(
    ...
)
複製程式碼

“競速”方法,引數與Promise.all()相同,不同的是,引數中的p1、p2、p3只要有一個改變狀態,promise就會立刻變成相同的狀態並執行對於的回撥

Promise.done() / Promise. finally()

Promise.done() 的用法類似 .then() ,可以提供resolved和rejected方法,也可以不提供任何引數,它的主要作用是在回撥鏈的尾端捕捉前面沒有被 .catch() 捕捉到的錯誤

Promise. finally() 接受一個方法作為引數,這個方法不管promise最終的狀態是怎樣,都一定會被執行

相關文章