關注「鬆寶寫程式碼」,精選好文,每日一題
加入我們一起學習,day day up
作者:saucxs | songEagle
來源:原創
一、前言
2020.12.23日剛立的flag,每日一題,題目型別不限制,可以是:演算法題,面試題,闡述題等等。
往期「每日一題」:
-
第2道「[每日一題]ES6中為什麼要使用Symbol?」(https://mp.weixin.qq.com/s/omeVJdtabo5MeN3DItDfWg)
-
第1道「一道面試題是如何引發深層次的靈魂拷問?」(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實現的最初版本
2、Promise的大致框架
大致框架有了,但是Promise狀態,resolve函式,reject函式,以及then等回撥沒有詳細處理
3、Promise的鏈式儲存
我們先看一個例子:
每間隔1秒列印一個數字,哈哈,這個不是真實的間隔1秒,汪汪,
這個的輸出是啥?
列印順序:1、2、3
這裡我們能確認的是:
- 讓a,b,c的只能在then的回撥接收到
- 在連續的非同步呼叫中,如何保證非同步函式的執行順序
Promise一個常見的需求就是連續執行兩個或者多個非同步操作,這種情況下,每一個後來的操作都在前面的操作執行成功之後,帶著上一步操作所返回的結果開始執行。這裡用setTimeout來處理.
4、Promise的狀態機制和執行順序
為了保證Promise的非同步操作時的順序執行,這裡給Promise加上狀態機制
5、Promise的遞迴執行
每個Promise後面連結一個物件,該物件包含onresolved,onrejected,子promise三個屬性.
當父Promise 狀態改變完畢,執行完相應的onresolved/onrejected的時候,拿到子promise,在等待這個子promise狀態改變,在執行相應的onresolved/onrejected。依次迴圈直到當前promise沒有子promise。
6、Promise的異常處理
每個Promise後面連結一個物件,該物件包含onresolved,onrejected,子promise三個屬性.
當父Promise 狀態改變完畢,執行完相應的onresolved/onrejected的時候,拿到子promise,在等待這個子promise狀態改變,在執行相應的onresolved/onrejected。依次迴圈直到當前promise沒有子promise。
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的結果都有可能不同。
8、Promise的值穿透
我們來看一下這個題的輸出:
最終打結果是1而不是2.
我們再來看一下這個題的輸出:
各種福利
「鬆寶寫程式碼」公眾號:開發知識體系構建,技術分享,專案實戰,實驗室,每日一題,帶你一起學習新技術,總結學習過程,讓你進階到高階資深工程師,學習專案管理,思考職業發展,生活感悟,充實中成長起來。問題或建議,請公眾號留言。
1、位元組內推福利
回覆「校招」獲取內推碼
回覆「社招」獲取內推
回覆「實習生」獲取內推
後續會有更多福利
2、學習資料福利
回覆「演算法」獲取演算法學習資料