NodeJS的Promise的用法

Javascript的特點是異步战惊,Javascript不能等待信柿,如果你實現(xiàn)某件需要等待的事情钠绍,你不能停在那里一直等待結(jié)果回來舆声,相反,底線是使用回調(diào)callback:你定義一個函數(shù)柳爽,這個函數(shù)只有等到結(jié)果可用時才能被調(diào)用媳握。

這種回調(diào)模型對于好的代碼組織是沒有問題的,但是也可以通過從原始回調(diào)切換到promise解決很多問題磷脯,將promise看成是一個標準的數(shù)據(jù)容器蛾找,這樣會簡化你的代碼組織,可以成為基于promise的架構(gòu)赵誓。

什么是Promise?

一個promise是一個帶有".then()"方法的對象打毛,其代表的是一個操作的結(jié)果可能還沒有或不知道,無論誰訪問這個對象俩功,都能夠使用".then()"方法加入回調(diào)等待操作出現(xiàn)成功結(jié)果或失敗時的提醒通知幻枉。

那么為什么這樣做好處優(yōu)于回調(diào)呢?標準的回調(diào)模式在我們處理請求時需要同時提供回調(diào)函數(shù):

request(url, function(error, response) {

// handle success or error.

});

doSomethingElse();

很不幸绑雄,這段代碼意味著這個request函數(shù)并不知道它自己什么時候能夠完成展辞,當然也沒有必要,我們最終通過回調(diào)傳遞結(jié)果万牺。這會導致多個回調(diào)形成了嵌套回調(diào),或者稱為回調(diào)陷阱洽腺。

queryTheDatabase(query, function(error, result) {

request(url, function(error, response) {

doSomethingElse(response, function(error, result) {

doAnotherThing(result, function(error, result) {

request(anotherUrl, function(error, response) {

...

});

});

});

});

});

Promise能夠解決這種問題脚粟,允許低層代碼創(chuàng)建一個request然后返回一個對象,其代表著未完成的操作蘸朋,讓調(diào)用者去決定應該加入什么回調(diào)核无。


Promise是什么?

promise是一個異步編程的抽象藕坯,它是一個返回值或拋出exception的代理對象团南,一般promise對象都有一個then方法,這個then方法是我們?nèi)绾潍@得返回值(成功實現(xiàn)承諾的結(jié)果值炼彪,稱為fulfillment)或拋出exception(拒絕承諾的理由吐根,稱為rejection),then是用兩個可選的回調(diào)作為參數(shù)辐马,我們可以稱為onFulfilled和OnRejected:

var promise = doSomethingAync()

promise.then(onFulfilled, onRejected)

當這個promise被解決了拷橘,也就是異步過程完成后,onFulfilled和OnRejected中任何一個將被調(diào)用,

因此冗疮,一個promise有下面三個不同狀態(tài):

pending待承諾 - promise初始狀態(tài)

fulfilled實現(xiàn)承諾 - 一個承諾成功實現(xiàn)狀態(tài)

rejected拒絕承諾 - 一個承諾失敗的狀態(tài)

以讀取文件為案例萄唇,下面是使用回調(diào)實現(xiàn)讀取文件后應該做什么事情(輸出打印):

readFile(function (err, data) {

if (err) return console.error(err)

console.log(data)

})

如果我們的readFile函數(shù)返回一個promise,那么我們可以如下實現(xiàn)同樣的邏輯(輸出打印):

var promise = readFile()

promise.then(console.log, console.error)

這里我們有了一個值promise代表的是異步操作术幔,我們能夠一直傳遞這個值promise另萤,任何人訪問這個值都能夠使用then來消費使用它,無論這個值代表的異步操作是否完成或沒有完成诅挑,我們也能保證異步的結(jié)果不會改變四敞,因為這個promise代表的異步操作只會執(zhí)行一次,狀態(tài)是要么fulfilled要么是rejected揍障。

理解Promise

Promise可能是不同于日常直覺目养,為了理解它,一些重要原理必須記牢: .then()總是返回一個新的promise.毒嫡,如下面代碼:

var promise = readFile()

var promise2 = promise.then(readAnotherFile, console.error)

這里then的參數(shù)readAnotherFile, console.error是代表異步操作成功后的動作onFulfilled或失敗后的動作OnRejected癌蚁,也就是說,讀取文件成功后執(zhí)行readAnotherFile函數(shù)兜畸,否則失敗打印記錄錯誤努释。這種實現(xiàn)是兩個中只有一種可能。

我們再看下面上述代碼如下:

var promise = readFile()

var promise2 = promise.then(function (data) {

return readAnotherFile() // 如果readFile成功咬摇,執(zhí)行readAnotherFile

}, function (err) {

console.error(err) // 如果readFile不成功伐蒂,記錄,但是還是執(zhí)行readAnotherFile

return readAnotherFile()

})

promise2.then(console.log, console.error) // readAnotherFile函數(shù)的執(zhí)行結(jié)果

因為then返回一個promise肛鹏,它意味著promise能夠被chain串行鏈條花逸邦,這樣能避免回調(diào)地獄:

readFile()

.then(readAnotherFile)

.then(doSomethingElse)

.then(...)

Promise法則有兩部分必須分離:

(1).then()總是返回一個新的promise,每次你調(diào)用它在扰,它不管回調(diào)做什么缕减,因為.then()在回調(diào)被調(diào)用之前已經(jīng)給了你一個承諾promise,回調(diào)的行為只影響承諾promise的實施芒珠,如果回調(diào)返回一個值桥狡,那么promise將使用那個值,如果這個值是一個promise皱卓,返回這個promise實施后的值給這個值裹芝,如果回調(diào)拋出錯誤,promise將拒絕錯誤娜汁。

(2)被.then()返回的promise是一個新的promise嫂易,它不同于那些.then()被調(diào)用的promise,promise長長的鏈條有時會好些隱藏這個事實存炮,不管如何炬搭,每次.then()調(diào)用都會產(chǎn)生一個新的promise蜈漓,這里必須注意的是你真正需要考慮的是你最后調(diào)用.then()可能代表失敗,那么如果你不捕獲這種失敗宫盔,那么容易導致你的錯誤exception消失融虽。

一些人認為.then()串聯(lián)鏈條調(diào)用很類似fluent風格,但是長長的promise鏈條會讓人迷惑灼芭,最后切分為一個個有意義的函數(shù):

function getTasks() {

return $http.get('http://example.com/api/v1/tasks')

.then(function(response) {

return response.data;

});

}

function getMyTasks() {

return getTasks()

.then(function(tasks) {

return filterTasks(tasks, {

owner: user.username

});

});

}

在這個例子中有额,兩個函數(shù)各自獲得一個promise,攜帶了一個回調(diào)函數(shù)彼绷。

有趣的Promise

同樣的promise能夠接受任何數(shù)目的回調(diào)巍佑,當一個Promise被解決實施后,其中所有回調(diào)函數(shù)都會被調(diào)用寄悯,此外萤衰,一個promise在被解決實施后,甚至可以接受一個新的回調(diào)猜旬,這些回調(diào)完成能以正常方式被調(diào)用脆栋,這就允許我們使用回調(diào)實現(xiàn)簡單形式的緩存:

var tasksPromise;

function getTasks() {

taskPromise = taskPromise || getTasksFromTheServer();

return taskPromise;

}

這個案例中,getTasks()函數(shù)可以被任意次數(shù)調(diào)用洒擦,它總是返回銅牙的promise椿争,其中函數(shù)getTasksFromTheServer()卻只是被調(diào)用一次。

Node.js error-first回調(diào)模式

在Node.js中使用Javascript Generators

Generator與Fiber比較

學習Javascript ES6幾個重要特性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熟嫩,一起剝皮案震驚了整個濱河市秦踪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌掸茅,老刑警劉巖椅邓,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異昧狮,居然都是意外死亡希坚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門陵且,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人个束,你說我怎么就攤上這事慕购。” “怎么了茬底?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵沪悲,是天一觀的道長。 經(jīng)常有香客問我阱表,道長殿如,這世上最難降的妖魔是什么贡珊? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮涉馁,結(jié)果婚禮上门岔,老公的妹妹穿的比我還像新娘。我一直安慰自己烤送,他們只是感情好寒随,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著帮坚,像睡著了一般妻往。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上试和,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天讯泣,我揣著相機與錄音,去河邊找鬼阅悍。 笑死好渠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的溉箕。 我是一名探鬼主播晦墙,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肴茄!你這毒婦竟也來了晌畅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤寡痰,失蹤者是張志新(化名)和其女友劉穎抗楔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拦坠,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡连躏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贞滨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片入热。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晓铆,靈堂內(nèi)的尸體忽然破棺而出勺良,到底是詐尸還是另有隱情,我是刑警寧澤骄噪,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布尚困,位于F島的核電站,受9級特大地震影響链蕊,放射性物質(zhì)發(fā)生泄漏事甜。R本人自食惡果不足惜谬泌,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逻谦。 院中可真熱鬧掌实,春花似錦、人聲如沸跨跨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勇婴。三九已至忱嘹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間耕渴,已是汗流浹背拘悦。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留橱脸,地道東北人础米。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像添诉,于是被迫代替她去往敵國和親屁桑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

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

  • 本文適用的讀者 本文寫給有一定Promise使用經(jīng)驗的人栏赴,如果你還沒有使用過Promise蘑斧,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,313評論 6 19
  • //本文內(nèi)容起初摘抄于 阮一峰 作者的譯文须眷,用于記錄和學習竖瘾,建議觀者移步于原文 概念: 所謂的Promise,...
    曾經(jīng)過往閱讀 1,240評論 0 7
  • 特點 Promise能將回調(diào)分離出來,在異步操作執(zhí)行之后,用鏈式方法執(zhí)行回調(diào),雖然es5用封裝函數(shù)也能實現(xiàn),但是如...
    一二三kkxx閱讀 623評論 0 1
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持花颗,譯者再次奉上一點點福利:阿里云產(chǎn)品券捕传,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 11,028評論 26 95
  • 短期靠波動 長期靠現(xiàn)金流
    坐井觀天闊閱讀 196評論 0 0