Promise

JS 的 Promise 看了好幾次了,大概清楚概念,但是一直心里沒底,也沒寫過代碼,今天把這些心虛的部分一波帶走。

Background

簡單聊一下背景,眾所周知 JavaScript 是以單線程的方式運行的。在某一時刻內(nèi)只能執(zhí)行特定的一個任務(wù),并且會阻塞其它任務(wù)的執(zhí)行。對于類似網(wǎng)絡(luò)請求等耗時的任務(wù),沒必要等任務(wù)執(zhí)行完后才繼續(xù)后面的操作。在這些任務(wù)完成前,JavaScript 完全可以往下執(zhí)行其他操作,當這些耗時的任務(wù)完成后則以回調(diào)的方式執(zhí)行相應(yīng)處理。這些就是 JavaScript 與生俱來的特性:異步與回調(diào)。

大概是這個樣子:

networkQuery(queryUrl, function(err, data){
  if(err){
    console.log("error!")
  } else {
    // handle data
  }
})

當然這也帶了一個坑,如果你需要執(zhí)行多個耗時操作,并且他們之間存在執(zhí)行結(jié)果數(shù)據(jù)之間的依賴,那你不得不把代碼寫成下面這樣。回調(diào)地獄

networkQuery(queryUrl, function(err, data){
  if(err){
    console.log("First query error!")
  } else {
    queryFromBackEnd(data.someUrl, function(err, data){
      if(err){
        console.log("Second query error!")
      } else {
         queryFromOtherSystem(data.otherUrl, function(err, data){
           if(err){
             console.log("Error!")
           } else {
             console.log("Finally get data in Callback Hell")
           }
         })
      }
    })
  }
})

邏輯簡單還好說,稍微復(fù)雜一點,第二天根本看不懂自己寫了什么。

Promise

解決回調(diào)地獄的其中第一種方式就是使用 Promise。

Promise,如字面所說:承諾。

假裝是代碼:

我承諾(promise)今天要學(xué)會使用 Promise。然后(then)等到今天結(jié)束的時候,可能實現(xiàn)了承諾(resolve),不過也有可能遇到(catch)沒有實現(xiàn)承諾的情況(reject)。

翻譯一下:

let learnPromise = new Promise(function(resolve, reject){
  // Wait until the end of the day.
  // Check result: Do I understand how to use Promise?
  let understand = false;
  if(understand){
    resolve("Absolutely!")
  } else {
    reject("Not yet")
  }
})

learnPromise.then(function(messageFromResolve){
  console.log("Understood ? " + messageFromResolve)
}).catch(function(messageFromReject){
  console.log("Understood ? " + messageFromReject)
})

// OUTPUT
// Understood ? Not yet

第一行創(chuàng)建了一個 Promise 對象,創(chuàng)建的時候傳入了一個函數(shù),在函數(shù)內(nèi)部進行耗時操作。

此外函數(shù)接收兩個參數(shù),這兩個參數(shù)都是函數(shù)。分別是實現(xiàn)了承諾的后續(xù)操作函數(shù) resolve,和沒有實現(xiàn)承諾的后續(xù)操作函數(shù) rejectresolvereject, 分別對應(yīng) 代碼的下半部分中 Promise 對象在調(diào)用 then() 時傳入的函數(shù),和調(diào)用 catch() 時傳入的函數(shù)。

注意Promise 對象 learnPromise 的使用方式,then()catch(), Promise 讓編寫異步代碼稍微看起來像在寫同步代碼一樣。

Multiple Promises

回到最初的例子,回調(diào)地獄。如果使用 Promise,則每個 query 方法都不直接使用回調(diào)函數(shù),而是返回一個 Promise 對象,調(diào)用的時候在每一個 resolve 函數(shù)的最后調(diào)用下一階段的 query 函數(shù),返回對應(yīng)的 Promise 對象(也就是在 then 中傳入函數(shù)的最后返回一個 Promise 對象),就可以在 then 方法之后繼續(xù) 調(diào)用 then。

query()
.then( function(){ /* Return a Promise instance */})
.then( function(){ /* Return a Promise instance */})
.then( function(){ /* Return a Promise instance */})
.catch()

就像這樣,我們把返回的結(jié)果 message 也作為參數(shù)傳到了下一個 Promise,在最后一個 Promise 的 resolve 中打印。

let networkQuery = function(message){
  return new Promise((resolve, reject) => {
    let data = "First query result, based on " + message
    resolve(data);
  })
}

let queryFromBackEnd = function(message){
  return new Promise((resolve, reject) => {
    let data =  "Second query result, based on " + message
    resolve(data);
  })
}

let queryFromOtherSystem = function(message){
  return new Promise((resolve, reject) => {
    let data = "Third query result, based on " + message
    resolve(data);
  })
}
    
networkQuery("nothing").then(tempData => {
  return queryFromBackEnd(tempData)
}).then(data => {
  return queryFromOtherSystem(data)
}).then(finalData => {
  console.log(finalData)
})

// OUTPUT
// Third query result, based on Second query result, based on First query result, based on nothing

Other condition

當然有的時候我們或許并不關(guān)心執(zhí)行的過程,只關(guān)心是否成功的執(zhí)行完了所有任務(wù),也可以這樣使用

Promise.all([firstOperation(), secondOperation(), thirdOperation()]).then(() =>{
  console.log("All finished")
  // do something else
})

或者只要其中一個執(zhí)行成功就可以了:

Promise.race([firstOperation(), secondOperation(), thirdOperation()]).then(() =>{
  console.log("One of them is finished")
  // do something else
})

最后,understand = true。

好了,今天就到這里了。

最后編輯于
?著作權(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)容