1. 程式人生 > >「每日一題」面試官問你對Promise的理解?可能是需要你能手動實現各個特性

「每日一題」面試官問你對Promise的理解?可能是需要你能手動實現各個特性

關注「鬆寶寫程式碼」,精選好文,每日一題 加入我們一起學習,day day up >作者:saucxs | songEagle >來源:原創 ## 一、前言 2020.12.23日剛立的flag,每日一題,題目型別不限制,可以是:演算法題,面試題,闡述題等等。 ![每日一題](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/daily_question.png) 往期「每日一題」: + 第2道[「[每日一題]ES6中為什麼要使用Symbol?」(https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg)](https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg) + 第1道[「一道面試題是如何引發深層次的靈魂拷問?」(https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1kdda3LA)](https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1kdda3LA) 接下來是第3道:談談你對 promise 的理解? ## 二、談談你對 promise 的理解? ### 1、我們簡單概括一下promise Promise 是 ES6 新增的語法,解決了回撥地獄的問題。 無論是ES6的Promise也好,jQuery的Promise也好,不同的庫有不同的實現,但是大家遵循的都是同一套規範,所以,Promise並不指特定的某個實現,它是一種規範,是一套處理JavaScript非同步的機制。 Promise 本質上就是一個綁定了回撥的物件,而不是將回調傳回函式內部。 所以,Promise在一定程度上解決了回撥函式的書寫結構問題,但回撥函式依然在主流程上存在,只不過都放到了then(...)裡面,和我們大腦順序線性的思維邏輯還是有出入的。 ### 2、我們說一下promise相關規範 + 可以把 Promise 看成一個狀態機。初始是 pending 狀態,可以通過函式 resolve 和 reject ,將狀態轉變為 resolved 或者 rejected 狀態,狀態一旦改變就不能再次變化。 + then 函式會返回一個 Promise 例項,並且該返回值是一個新的例項而不是之前的例項。因為 Promise 規範規定除了 pending 狀態,其他狀態是不可以改變的,如果返回的是一個相同例項的話,多個 then 呼叫就失去意義了。 + then 方法可以被同一個 promise 呼叫多次。 + 值穿透 ## 三、promise 是如何實現的? ### 1、Promise的簡單使用 ![Promise的簡單使用](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon.png) 我們通過這種使用構建Promise實現的最初版本 ### 2、Promise的大致框架 大致框架有了,但是Promise狀態,resolve函式,reject函式,以及then等回撥沒有詳細處理 ![Promise的大致框架](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_1.png) ### 3、Promise的鏈式儲存 我們先看一個例子: ![Promise的鏈式儲存](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_2.png) 每間隔1秒列印一個數字,哈哈,這個不是真實的間隔1秒,汪汪, 這個的輸出是啥? 列印順序:1、2、3 這裡我們能確認的是: + 讓a,b,c的只能在then的回撥接收到 + 在連續的非同步呼叫中,如何保證非同步函式的執行順序 Promise一個常見的需求就是連續執行兩個或者多個非同步操作,這種情況下,每一個後來的操作都在前面的操作執行成功之後,帶著上一步操作所返回的結果開始執行。這裡用setTimeout來處理. ![Promise的鏈式儲存](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_3.png) ### 4、Promise的狀態機制和執行順序 為了保證Promise的非同步操作時的順序執行,這裡給Promise加上狀態機制 ![Promise的狀態機制和執行順序](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_4.png) ### 5、Promise的遞迴執行 每個Promise後面連結一個物件,該物件包含onresolved,onrejected,子promise三個屬性. 當父Promise 狀態改變完畢,執行完相應的onresolved/onrejected的時候,拿到子promise,在等待這個子promise狀態改變,在執行相應的onresolved/onrejected。依次迴圈直到當前promise沒有子promise。 ![Promise的遞迴執行](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_5.png) ### 6、Promise的異常處理 每個Promise後面連結一個物件,該物件包含onresolved,onrejected,子promise三個屬性. 當父Promise 狀態改變完畢,執行完相應的onresolved/onrejected的時候,拿到子promise,在等待這個子promise狀態改變,在執行相應的onresolved/onrejected。依次迴圈直到當前promise沒有子promise。 ![Promise的異常處理](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_6.png) ### 7、Promise的then的實現 then 方法是 Promise 的核心,這裡做一下詳細介紹。 ``` promise.then(onFulfilled, onRejected) ``` 一個 Promise 的then接受兩個引數: onFulfilled和onRejected(都是可選引數,並且為函式,若不是函式將被忽略) + onFulfilled 特性: 當 Promise 執行結束後其必須被呼叫,其第一個引數為 promise 的終值,也就是 resolve 傳過來的值 在 Promise 執行結束前不可被呼叫 其呼叫次數不可超過一次 + onRejected 特性 當 Promise 被拒絕執行後其必須被呼叫,第一個引數為 Promise 的拒絕原因,也就是reject傳過來的值 在 Promise 執行結束前不可被呼叫 其呼叫次數不可超過一次 + 呼叫時機 onFulfilled 和 onRejected 只有在執行環境堆疊僅包含平臺程式碼時才可被呼叫(平臺程式碼指引擎、環境以及 promise 的實施程式碼) + 呼叫要求 onFulfilled 和 onRejected 必須被作為函式呼叫(即沒有 this 值,在 嚴格模式(strict) 中,函式 this 的值為 undefined ;在非嚴格模式中其為全域性物件。) + 多次呼叫 then 方法可以被同一個 promise 呼叫多次 當 promise 成功執行時,所有 onFulfilled 需按照其註冊順序依次回撥 當 promise 被拒絕執行時,所有的 onRejected 需按照其註冊順序依次回撥 + 返回 then方法會返回一個Promise,關於這一點,Promise/A+標準並沒有要求返回的這個Promise是一個新的物件,但在Promise/A標準中,明確規定了then要返回一個新的物件,目前的Promise實現中then幾乎都是返回一個新的Promise(詳情)物件,所以在我們的實現中,也讓then返回一個新的Promise物件。 ``` promise2 = promise1.then(onFulfilled, onRejected); ``` - 如果 onFulfilled 或者 onRejected 返回一個值 x ,則執行下面的 Promise 解決過程:[[Resolve]](promise2, x) - 如果 onFulfilled 或者 onRejected 丟擲一個異常 e ,則 promise2 必須拒絕執行,並返回拒因 e - 如果 onFulfilled 不是函式且 promise1 成功執行, promise2 必須成功執行並返回相同的值 - 如果 onRejected 不是函式且 promise1 拒絕執行, promise2 必須拒絕執行並返回相同的拒因 不論 promise1 被 reject 還是被 resolve , promise2 都會被 resolve,只有出現異常時才會被 rejected。 每個Promise物件都可以在其上多次呼叫then方法,而每次呼叫then返回的Promise的狀態取決於那一次呼叫then時傳入引數的返回值,所以then不能返回this,因為then每次返回的Promise的結果都有可能不同。 ![Promise的then的實現](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_7.png) ### 8、Promise的值穿透 ![Promise的then的實現](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_8.png) 我們來看一下這個題的輸出: ![Promise的then的實現](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_9.png) 最終打結果是1而不是2. 我們再來看一下這個題的輸出: ![Promise的then的實現](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/promise/carbon_10.png) ## 各種福利 ![鬆寶寫程式碼](https://raw.githubusercontent.com/saucxs/full_stack_knowledge_list/master/daily-question/dongtai.gif) 「鬆寶寫程式碼」公眾號:開發知識體系構建,技術分享,專案實戰,實驗室,每日一題,帶你一起學習新技術,總結學習過程,讓你進階到高階資深工程師,學習專案管理,思考職業發展,生活感悟,充實中成長起來。問題或建議,請公眾號留言。 ### 1、位元組內推福利 回覆「校招」獲取內推碼 回覆「社招」獲取內推 回覆「實習生」獲取內推 後續會有更多福利 ### 2、學習資料福利 回覆「演算法」獲取演算法學習資料 ### 3、每日一題 + 3、本文就是第3道:談談你對 promise 的理解? + 第2道[「[每日一題]ES6中為什麼要使用Symbol?」(https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg)](https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg) + 第1道[「一道面試題是如何引發深層次的靈魂拷問?」(https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1kdda3LA)](https://mp.weixin.qq.com/s/O8j9gM5tD5rjLz1k