從代碼實例理解Promise

說來用Promise也有一段時間了,一直把它當(dāng)成一個callback hell的解決方案在用,使用它的時候,并沒有真正的了解它。最近同事給我推薦了一篇文章:We have a problem with Promise, 才發(fā)現(xiàn)Promise的門道還是很多的,讀過這篇文章后,我重新整理了一下對Promise的認(rèn)知,英文還可以的同學(xué)一定要看原文。

Promise的基本用法:

常見的Promise用法如下:

somePromise()
  .then(function () { 
    // I'm inside a then() function!
  })
  .then(function (previousResult) { })
  .catch(error) {errorHandler};

在then()方法中,可能出現(xiàn)三種情況:

  1. 返回一個新的Promise
somePromise().then(function () { 
    return anotherPromise();
  });

通過then()方法,把多個異步操作順序的執(zhí)行下去。

  1. 返回一個值
somePromise().then(function () { 
    return somevalue;
  });

通過這個方式可以把同步操作插入到異步操作流中,以統(tǒng)一的形式來管理操作流的時序。

  1. Throw一個異常
somePromise().then(function () { 
    throw new Error('You bad bad!'); 
  });

不管是前面是同步計算值,還是異步Promise, 只要throw出異常,都會被后面的catch抓住,進(jìn)行相應(yīng)的處理。

上面的一切都看起來非常美好,非常簡單,但是你真的理解Promise了嗎?

理解Promise執(zhí)行的時序

Promise對程序來說,主要的作用是:有異步操作時,能夠讓程序仍然具有同步操作時的時序,return, throw exception等基礎(chǔ)程序功能。因此,當(dāng)使用Promise最重要的就是清楚自己寫出來的代碼在執(zhí)行時的時序,以及前一步的結(jié)果如何傳遞給后續(xù)的操作。

假設(shè)doSomething*()都會返回一個Promise,你是否能清楚的描述出下面的幾段代碼的時序,以及每個方法接收的參數(shù)?

Code 1:
doSomething()
  .then(function () { return doSomethingElse();})
  .then(finalHandler);

Code 2:
doSomething()
  .then(function () { doSomethingElse();})
  .then(finalHandler);

Code 3:
doSomething()
  .then(doSomethingElse())
  .then(finalHandler);

Code 4:
doSomething()
  .then(doSomethingElse)
  .then(finalHandler);

Code 5:
Promise.all([
  doSomethingOne(), 
  doSomethingTwo(), 
  doSomethingThree()
])
  .then(function (previusResult) { 
    return doSomethingElse(previusResult);
  })
  .then(finalHandler);
?```

答案:

Code 1: doSomethingElse會等待doSomething會先執(zhí)行到返回一個Promise,
但是因為doSomethingElse的wrapper function沒有接收上一步的返回值。
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|

Code 2: 沒有return語句, 默認(rèn)返回undefined, 下一步執(zhí)行不會等待上一步執(zhí)行完成。
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(undefined)
|------------------|

Code 3: 第一個then()方法內(nèi)部的沒有function Wrapper, 在構(gòu)建Promise時就會執(zhí)行doSomethingElse(),
并返回結(jié)果給下一步finalHandler。
doSomething
|-----------------|
doSomethingElse(undefined)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|

Code 4: Promise之間可以在then()方法之間直接連接,這樣可以節(jié)省不少代碼。
doSomething
|-----------------|
doSomethingElse(resultOfDoSomething)
|------------------|
finalHandler(resultOfDoSomethingElse)
|------------------|```

Code 5: Promise.all會并發(fā)的執(zhí)行參數(shù)中所有的Promise, 并等待所有的Promise的返回結(jié)果,然后封裝為Array返回給后續(xù)的操作。
doSomethingOne
|-----------------|
doSomethingTwo
|-----------------|
doSomethingThree
|-----------------|
                  doSomethingElse([resultOfOne,resultOfTwo, resultOfThree])
                  |------------------|
                                     finalHandler(resultOfDoSomethingElse)
                                     |------------------|```

###小測驗

**問題一:**下面的代碼會有什么問題?
```?{JAVASCRIPT}
DialogActions.hide()  
  .then(() => {  
   Actions.deletePartOfA()  
  .then(() =>{   
   Actions.retrieveA()  
  });

這段代碼原本的目的是刪除一個Resource A的某個部分之后,重新請求Resource A以保證本地和遠(yuǎn)端的Resource同步,但是Actions.deletePartOfA() 沒有return,最后Actions.retrieveA()和Actions.deletePartOfA()會同時執(zhí)行,因此最后Actions.retrieveA()得到的Resource A并沒有刪除那個部分。

問題二:下面兩份代碼有什么不同?

Code 1:
Promise.resolve()  
  .then(() => { throw new Error('Test')})  
  .catch((e) => { console.error(e)});
Code 2:
Promise.resolve()  
  .then(() => { throw new Error('Test')}, (e) =>{ console.error(e);})

Code 2無法打印出error, 因為當(dāng)RejectHandler無法捕獲自己平級的ResolveHandler拋出的異常。

問題三:下面的兩份代碼會輸出什么結(jié)果?

Code 1:
Promise.resolve('foo')
  .then(Promise.resolve('bar'))
  .then(function (result) { console.log(result);});

Code 2:
Promise.resolve('foo')
  .then(function () { return Promise.resolve('bar');})
  .then(function (result) { console.log(result);});

Code 1會輸出'foo', Code 2會輸出 'bar'。當(dāng)在then()方法中直接放置一個Promise定義(沒有function wrapper)時,效果等同then(null),這種情況下,Promise的結(jié)果會穿透這個then(null).

問題四:下面的兩份代碼會輸出什么結(jié)果?

function throwError() {  throw new Error('Test');};
Code 1:
Promise.resolve(throwError())  
  .catch(error => { console.log(error); });

Code 2:
Promise.resolve()  
  .then(() =>{ throwError() })  
  .catch(error => { console.log(error); });```
Code 1不能捕獲異常,Code 2能夠正常捕獲異常, Code1在構(gòu)建Promise時就拋出異常,這時catch語句還沒準(zhǔn)備好接收異常。

###Promise推薦實踐

1. 每個then()方法都使用return語句。
2. 每個then()方法中都使用function wrapper。
3. 每個Promise最后都接一個catch幫助定位錯誤。
4. 使用catch捕獲異常而非rejectHandler。
5. 使用Promise.resolve()創(chuàng)建Promise
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容