Promise

JS 的 Promise 看了好幾次了逝淹,大概清楚概念啄枕,但是一直心里沒(méi)底,也沒(méi)寫(xiě)過(guò)代碼蚓耽,今天把這些心虛的部分一波帶走渠牲。

Background

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

大概是這個(gè)樣子:

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

當(dāng)然這也帶了一個(gè)坑序宦,如果你需要執(zhí)行多個(gè)耗時(shí)操作,并且他們之間存在執(zhí)行結(jié)果數(shù)據(jù)之間的依賴背苦,那你不得不把代碼寫(xiě)成下面這樣互捌。回調(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")
           }
         })
      }
    })
  }
})

邏輯簡(jiǎn)單還好說(shuō)行剂,稍微復(fù)雜一點(diǎn)秕噪,第二天根本看不懂自己寫(xiě)了什么。

Promise

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

Promise腌巾,如字面所說(shuō):承諾。

假裝是代碼:

我承諾(promise)今天要學(xué)會(huì)使用 Promise铲觉。然后(then)等到今天結(jié)束的時(shí)候澈蝙,可能實(shí)現(xiàn)了承諾(resolve),不過(guò)也有可能遇到(catch)沒(méi)有實(shí)現(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)建了一個(gè) Promise 對(duì)象灯荧,創(chuàng)建的時(shí)候傳入了一個(gè)函數(shù),在函數(shù)內(nèi)部進(jìn)行耗時(shí)操作盐杂。

此外函數(shù)接收兩個(gè)參數(shù)逗载,這兩個(gè)參數(shù)都是函數(shù)。分別是實(shí)現(xiàn)了承諾的后續(xù)操作函數(shù) resolve链烈,和沒(méi)有實(shí)現(xiàn)承諾的后續(xù)操作函數(shù) reject厉斟。resolvereject, 分別對(duì)應(yīng) 代碼的下半部分中 Promise 對(duì)象在調(diào)用 then() 時(shí)傳入的函數(shù)强衡,和調(diào)用 catch() 時(shí)傳入的函數(shù)擦秽。

注意Promise 對(duì)象 learnPromise 的使用方式,then()catch(), Promise 讓編寫(xiě)異步代碼稍微看起來(lái)像在寫(xiě)同步代碼一樣号涯。

Multiple Promises

回到最初的例子目胡,回調(diào)地獄。如果使用 Promise链快,則每個(gè) query 方法都不直接使用回調(diào)函數(shù)誉己,而是返回一個(gè) Promise 對(duì)象,調(diào)用的時(shí)候在每一個(gè) resolve 函數(shù)的最后調(diào)用下一階段的 query 函數(shù)域蜗,返回對(duì)應(yīng)的 Promise 對(duì)象(也就是在 then 中傳入函數(shù)的最后返回一個(gè) Promise 對(duì)象)巨双,就可以在 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ù)傳到了下一個(gè) Promise筑累,在最后一個(gè) 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

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

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

或者只要其中一個(gè)執(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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贱田,一起剝皮案震驚了整個(gè)濱河市缅茉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌男摧,老刑警劉巖蔬墩,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異耗拓,居然都是意外死亡拇颅,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門帆离,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蔬蕊,“玉大人,你說(shuō)我怎么就攤上這事哥谷“逗唬” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵们妥,是天一觀的道長(zhǎng)猜扮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)监婶,這世上最難降的妖魔是什么旅赢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任齿桃,我火速辦了婚禮,結(jié)果婚禮上煮盼,老公的妹妹穿的比我還像新娘短纵。我一直安慰自己,他們只是感情好僵控,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布香到。 她就那樣靜靜地躺著,像睡著了一般报破。 火紅的嫁衣襯著肌膚如雪悠就。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天充易,我揣著相機(jī)與錄音梗脾,去河邊找鬼。 笑死盹靴,一個(gè)胖子當(dāng)著我的面吹牛炸茧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鹉究,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宇立,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼踪宠!你這毒婦竟也來(lái)了自赔?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柳琢,失蹤者是張志新(化名)和其女友劉穎绍妨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體柬脸,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡他去,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了倒堕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灾测。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖垦巴,靈堂內(nèi)的尸體忽然破棺而出媳搪,到底是詐尸還是另有隱情,我是刑警寧澤骤宣,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布秦爆,位于F島的核電站,受9級(jí)特大地震影響憔披,放射性物質(zhì)發(fā)生泄漏等限。R本人自食惡果不足惜爸吮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望望门。 院中可真熱鬧形娇,春花似錦、人聲如沸筹误。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纫事。三九已至勘畔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丽惶,已是汗流浹背炫七。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钾唬,地道東北人万哪。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像抡秆,于是被迫代替她去往敵國(guó)和親奕巍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容