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