Promise 到底是什么?看这个小故事
大家好,我是若川,點(diǎn)此加我微信進(jìn)源碼群,一起學(xué)習(xí)源碼。
還可以進(jìn)《劍指前端offer》交流群。
另外,可以進(jìn)群免費(fèi)看下周六Vue專場直播,有尤雨溪分享「Vue3 生態(tài)現(xiàn)狀以及展望」
如果你還是一個(gè) JavaScript 初學(xué)者,你可能要糾結(jié)一下 Promise 到底是什么。
最近我發(fā)了一條動態(tài),描述了這個(gè)問題,我被大家的反饋震驚到了。所以我決定寫一篇關(guān)于 Promise 的教程。
我看過很多關(guān)于 Promise 的文章,但大部分教程都沒有通過類比的方式解釋清楚 Promise 到底是什么。初學(xué)者搞不懂 Promise 的根本原因是他們不知道 Promise 是做什么的,以及如何在簡單和復(fù)雜的場景中使用它。
因此在這篇教程中,我將通過一個(gè)小故事來解釋什么是 Promise、Promise 是如何工作的。同時(shí)我也會通過一些代碼示例來說明在 JavaScript 中如何使用 Promise。
什么是 Promise
想象一下,你準(zhǔn)備面試某個(gè)公司的前端工程師。
你走進(jìn)面試會場,當(dāng)面試馬上要開始時(shí)你發(fā)現(xiàn)簡歷忘帶了,這時(shí)你怎么辦?
你沒有氣餒。因?yàn)槟愫苄疫\(yùn),你有一個(gè)室友。
你馬上給室友打電話尋求幫助,懇求室友幫你找到簡歷。你的室友承諾他一旦找到就立馬回你消息。
假設(shè)簡歷被找到,室友給你回復(fù)信息:
“太好了,我找到你的簡歷了!”
但是如果室友沒有找到,他就要回復(fù)一條失敗的信息,并解釋他為什么沒有找到簡歷。比如,他可能給正在面試的你發(fā)如下信息:
“對不起,我沒有找到你的簡歷,因?yàn)槟愕谋kU(xiǎn)柜鑰匙丟了。”
與此同時(shí),面試還要繼續(xù)。但面試官并沒有拿到真實(shí)的簡歷,而是得到一個(gè)正在找簡歷的承諾,同時(shí)面試官把該簡歷的狀態(tài)設(shè)置成進(jìn)行中(PENDING)。
你回答了所有問題。但不幸的是,能否得到這個(gè)工作還要依賴你簡歷的最終狀態(tài)(FINAL STATUS)。
你的室友終于回消息了。正如我們前面討論過的,如果他沒有找到簡歷,他就需要發(fā)一個(gè)失敗的信息并解釋為什么沒有找到。
如果是這種情況,面試結(jié)束,你被拒絕(Rejected)了。
如果室友找到了簡歷,他會很高興的告訴你他找到了,而你將繼續(xù)面試,并獲得(FULFILL)這份工作。
如何把上述過程翻譯成 JS 代碼
室友承諾找簡歷并回復(fù)信息的過程等同于我們在 JavaScript 中定義一個(gè) Promise。定義 Promise 并不能直接或立即獲得返回值,而是返回一個(gè) Promise 對象。這個(gè) Promise 對象在一段時(shí)間后會接收返回值。
Promise 對象是異步的,這就意味著程序需要花點(diǎn)時(shí)間才能獲得結(jié)果。這和找簡歷是一樣的,都需要花點(diǎn)時(shí)間去找。
基于這個(gè)原因,在找的這個(gè)時(shí)間里,面試官并不是什么都沒做,而是基于簡歷一會兒就找到的承諾,他們依然開始面試候選人。在這個(gè)場景里,我們用簡歷一會兒就找到的承諾替換了真實(shí)的簡歷。
同理,JS 引擎也并不是等著什么也不做,而是繼續(xù)執(zhí)行后續(xù)代碼,并將返回的Promise對象狀態(tài)設(shè)置為 Pending。
回復(fù)信息包含是否找到簡歷的狀態(tài)信息。對于Promise對象來說,回復(fù)信息被稱作返回值。
如果回復(fù)信息是 “success”,我們將錄取候選人。如果是 “failure”,我們不錄取該候選人。
在 Promise 中,我們通過回調(diào)函數(shù)處理Promise的返回值。這些處理函數(shù)定義在then()方法中。
為了指定如何調(diào)用回調(diào)函數(shù),需要使用以下兩個(gè)方法:
resolve(value): 表明 Promise 任務(wù)成功,調(diào)用then()的成功回調(diào)函數(shù)。
reject(error): 表明 Promise 任務(wù)失敗,調(diào)用then()的錯誤回調(diào)函數(shù)。
如果 Promise 成功,則調(diào)用成功回調(diào),如果失敗,調(diào)用失敗回調(diào)。
在異步任務(wù)完成之前,Promise 只是一個(gè)占位符。當(dāng)你定義了一個(gè) Promise,你并不會立即獲得返回值,而是獲得一個(gè) Promise 對象。
如何在 JavaScript 中使用 Promise
你可以通過Promise類定義一個(gè) Promise 對象。
const?myPromise?=?new?Promise((resolve,?reject)?=>?{setTimeout(()?=>?{resolve('this?is?the?eventual?value?the?promise?will?return');},?3000); });console.log(myPromise);示例 1
在控制臺運(yùn)行將返回一個(gè)Promise對象:
除了通過構(gòu)造函數(shù)聲明一個(gè) Promise 對象外,還可以使用 Promise 內(nèi)置的 API 進(jìn)行聲明:
示例 2
示例 1 中的 Promise 等待 3s 后獲取到成功返回的信息:this is the eventual...,而示例 2 中將立即獲取到成功返回的信息。
JavaScript Promise 中的錯誤處理
Promise 對象也能被_rejected_。大多數(shù)時(shí)候,rejected ?的發(fā)生是因?yàn)閳?zhí)行異步任務(wù)的時(shí)候拋出了錯誤,此時(shí)就會調(diào)用reject()方法。
下面的示例展示了一個(gè) Promise 對象是如何執(zhí)行 reject 方法的:
const?myPromise?=?new?Promise((resolve,?reject)?=>?{let?a?=?false;setTimeout(()?=>?{return?(a)???resolve('a?is?found!'):?reject('sorry,?no?a');},?3000); });示例 3
你能想到 Promise 被 rejected 的原因嗎?如果你的答案是:a的值是 false,那么恭喜你答對了。
在示例 3 中,代碼執(zhí)行 3s 后將調(diào)用 reject 方法,因?yàn)?a)?表達(dá)式的值是 false,所以觸發(fā)reject方法。
Promise 的鏈?zhǔn)秸{(diào)用
當(dāng) Promise 返回了某個(gè)值,通常你都會對返回值進(jìn)行處理。
比如,你發(fā)送了一個(gè)網(wǎng)絡(luò)請求,你期望獲取數(shù)據(jù)并展示在頁面上。
你可以定義兩個(gè)回調(diào)函數(shù),當(dāng) Promise 返回成功或失敗時(shí)進(jìn)行回調(diào)。這兩個(gè)回調(diào)函數(shù)定義在then()內(nèi):
const?anotherPromise?=?new?Promise((resolve,?reject)?=>?{setTimeout(()?=>?{resolve('this?is?the?eventual?value?the?promise?will?return');},?3000); });//?CONTINUATION anotherPromise .then(value?=>?{?console.log(value)?})示例 4
示例 4 的代碼在 3s 后返回成功信息:
原則上你可以無限鏈?zhǔn)秸{(diào)用,調(diào)用鏈會依次執(zhí)行,而且前一個(gè) then 的返回值作為參數(shù)傳入后一個(gè) then。
示例 5
但我們還是遺漏了重要的內(nèi)容。
要時(shí)刻記住,then()方法必須有兩個(gè)回調(diào)函數(shù):第一個(gè)參數(shù)是成功回調(diào),第二個(gè)參數(shù)是錯誤回調(diào)。
在示例 4 和示例 5 中都沒有傳入第二個(gè)回調(diào)函數(shù)。因此,如果代碼報(bào)錯,就沒有錯誤回調(diào)捕獲錯誤信息。
如果你執(zhí)意要在then()中只定義一個(gè)回調(diào)函數(shù)(即成功回調(diào)),那么你就需要在 Promise 調(diào)用鏈的末端調(diào)用catch()方法捕獲任何可能的報(bào)錯信息。
如何在 JS 中使用catch()方法
在 Promise 調(diào)用鏈上,無論哪個(gè)環(huán)節(jié)報(bào)錯,catch()方法都會被調(diào)用。
const?myPromise?=?new?Promise((resolve,?reject)?=>?{let?a?=?false;setTimeout(()?=>?{return?(a)???resolve('a?is?found!'):?reject('sorry,?no?a');},?3000); });?myPromise .then(value?=>?{?console.log(value)?}) .catch(err?=>?{?console.log(err)?});示例 6
因?yàn)閙yPromise最終狀態(tài)是 rejected,then()方法中的成功回調(diào)被忽略。而catch()方法中的錯誤回調(diào)被執(zhí)行,并在控制臺打印如下錯誤信息:
寫在最后
JavaScript 中的 Promise 是一個(gè)運(yùn)行異步任務(wù)的強(qiáng)大功能。大部分情況下,在前端面試時(shí),面試官都會問一些關(guān)于 Promise 的問題。
在這片文章中,我已經(jīng)解釋了 Promise 的簡單應(yīng)用場景,也通過示例的方式展示了基本用法。
希望你能從文章中獲取有用的知識。如果你喜歡編程教程,點(diǎn)擊查看我的博客。我會經(jīng)常發(fā)布一些有關(guān)軟件開發(fā)的文章。
再次感謝您的閱讀,再會。
P/S: ?如果你也在學(xué)習(xí) JavaScript,我也創(chuàng)建了一個(gè)電子書,上面有 50 個(gè)關(guān)于 js 的主題,而且都是我親自手繪的哦。
原文鏈接:https://www.freecodecamp.org/news/what-is-promise-in-javascript-for-beginners/
作者:Kingsley Ubah
譯者:wangzili
最后預(yù)告福利:掃下方二維碼加我微信 ruochuan12,可以拉你進(jìn)群免費(fèi)觀看10月23日的前端早早聊?Vue 專場直播,大咖云集?,更有「尤雨溪」分享「Vue3 生態(tài)現(xiàn)狀以及展望」。?另外還可以送50個(gè)錄播視頻和PPT~
最近組建了一個(gè)湖南人的前端交流群,如果你是湖南人可以加我微信?ruochuan12?私信 湖南?拉你進(jìn)群。
推薦閱讀
1個(gè)月,200+人,一起讀了4周源碼
我歷時(shí)3年才寫了10余篇源碼文章,但收獲了100w+閱讀
老姚淺談:怎么學(xué)JavaScript?
我在阿里招前端,該怎么幫你(可進(jìn)面試群)
·················?若川簡介?·················
你好,我是若川,畢業(yè)于江西高校。現(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列
從2014年起,每年都會寫一篇年度總結(jié),已經(jīng)寫了7篇,點(diǎn)擊查看年度總結(jié)。
同時(shí),最近組織了源碼共讀活動
識別上方二維碼加我微信、拉你進(jìn)源碼共讀群
今日話題
略。歡迎分享、收藏、點(diǎn)贊、在看我的公眾號文章~
總結(jié)
以上是生活随笔為你收集整理的Promise 到底是什么?看这个小故事的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(3183):ant-desig
- 下一篇: Milogs客户销售工作日志软件系统简介