Promise最佳實踐(轉)


本文作者:IMWeb dekuchen 原文出處:IMWeb社區 未經同意,禁止轉載

有關Promise的幾個問題

基礎概念

一:什么是Promise

國內比較流行的看法:

阮一峰: Promise 對象

Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標准,統一了用法,原生提供了Promise對象。

Promise 真正的規范,一篇長文。

https://promisesaplus.com/

截取幾段:

Terminology

  1. “promise” is an object or function with a then method whose behavior conforms to this specification.
  2. “thenable” is an object or function that defines a then method.
  3. “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
  4. “exception” is a value that is thrown using the throw statement.
  5. “reason” is a value that indicates why a promise was rejected.

promise-states

從問題來看

1. 是否可以使用return 代替 resolve

不可以,無法實現鏈式調用,且不符合規范。

示例:

const testReturn = (a:boolean):Promise<any> =>{ return new Promise((resolve,reject)=>{ if(a){ return 'this is return'; resolve('true'); console.log('this will not be exec'); throw new Error('error'); }else{ reject('false'); } }) } 

執行結果:

 ~/chen/FE/winSep/codes/javascript/es6promise/src  ts-node return.ts Promise { <pending> } 
  1. 無法改變狀態
  2. 無法鏈式調用

2. 使用throw還是reject?

答案: 使用reject而不是throw

示例:不會被catch的throw Error

const testReturn = (a:boolean):Promise<any> =>{ return new Promise((resolve,reject)=>{ if(a){ resolve('true'); console.log('this will be exec'); throw new Error('error'); }else{ reject('false'); } }) } console.log(testReturn(true)); 

執行結果

 ~/chen/FE/winSep/codes/javascript/es6promise/src  ts-node return.ts this will be exec Promise { 'true' } 

解釋:

Promise的構造函數,以及被 then 調用執行的函數基本上都可以認為是在 try…catch 代碼塊中執行的,所以在這些代碼中即使使用 throw ,程序本身也不會因為異常而終止。Promise的狀態也不會發生改變。

示例:不使用reject而使用throw

如果在Promise中使用 throw 語句的話,會被 try...catch 住,最終promise對象也變為Rejected狀態。

var promise = new Promise(function(resolve, reject){ throw new Error("message"); }); promise.catch(function(error){ console.error(error);// => "message" }); 

運行

Error: message 

代碼像這樣其實運行時倒也不會有什么問題,但是如果想把 promise 設置為Rejected狀態的話,使用 reject 方法則更顯得合理。

所以上面的代碼可以改寫為下面這樣。

var promise = new Promise(function(resolve, reject){ reject(new Error("message")); }); promise.catch(function(error){ console.error(error);// => "message" }) 

總結:如果在Promise中使用 throw 語句的話,會被 try...catch 住,最終promise對象也變為Rejected狀態。

2. Promise的執行時間

1. resolve后面的代碼會不會被執行?

當沒有Error的時候, resolve會將Promise.then放在微任務隊列中,當所有的宏任務執行結束的時候,執行微任務隊列。
const testReturn = (a:boolean):Promise<any> =>{ return new Promise((resolve,reject)=>{ if(a){ resolve('exec true'); console.log('this will be exec'); // throw new Error('error'); }else{ reject('false'); } }) } testReturn(true).then(str=>{ console.log(str); }) 

執行結果

this will be exec exec true 
當有Error的時候,Error后面的代碼不會被執行,但是Promise的結果依舊是fulfilled
const testReturn = (a:boolean):Promise<any> =>{ return new Promise((resolve,reject)=>{ if(a){ resolve('exec true'); console.log('this will be exec'); throw new Error('error'); console.log('this will not be exec') }else{ reject('false'); } }) } testReturn(true).then(str=>{ console.log(str); // console.log(testReturn) }).catch(err=>{ console.log('err: ',err); }) 

執行結果

this will be exec exec true 

當Promise遇到setTimeout

看例子:

const testReturn = (a:boolean):Promise<any> =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ if(a){ resolve('exec true'); console.log('this will be second exec'); }else{ reject('false'); } }) console.log('this will first be execd'); }) } testReturn(true).then(str=>{ console.log(str); // console.log(testReturn) }).catch(err=>{ console.log('err: ',err); }) 

結果

this will first be execd this will be second exec exec true 

解釋:

時間 宏任務隊列 微任務隊列
1 console.log('this will first be execd')  
2 setTimeout  
3   resolve('exec true');//延遲:因為宏任務沒有執行完
4 console.log('this will be second exec');  
   

最終執行順序:

1->2->4(宏任務結束)->3(微任務結束) 

async/await 與Promise

一句話總結:await等的就是一個Promise。如果等的不是Promise,那加了await和不加沒區別

  1. 將常規的回調轉變為Promise的方法
function util(args,callback){ if(err){ return callback(err); }else{ return callback(); } } //調用 util(args,(err)=>{ if(err){ }else{ } }) //Promisify function utilPromise(args){ return new Promise((resolve,reject)=>{ if(err){ reject(err) }else{ resolve(); } }) } //調用 utilPromise.then().catch() 
  1. Promise轉換為async/await的方法
async init(){ try{ await utilPromise();//resolve狀態 }catch(e){ throw new Error(e); //reject狀態 } }


免責聲明!

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



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