Promise很復(fù)雜..恩..原來覺得不就是詞法作用域嗎, 原來覺得詞法作用域不就是調(diào)用時(shí)的堆棧是定義時(shí)的嘛 結(jié)果...一個(gè)簡單概念被玩成了這樣..
promise.js源碼從https://blog.csdn.net/qq_22844483/article/details/73655738
所得 謝謝原作者(未申請轉(zhuǎn)載 啊哈) 原本他的意思是從0寫一個(gè)promise 但是promise的鏈?zhǔn)秸{(diào)用部分看著暈暈的 為什么呢 因?yàn)檎騺砜紤]像我這種菜鳥想不通啊 也罷 那就逆向來想吧 跟一下堆棧 沒成想 兩個(gè)then就20多個(gè)堆棧 一步一步跟我來 反向完了來正向 非把它搞定不可
使用的promise.js是簡版 只有resolve而沒有其他實(shí)現(xiàn)(包括.all/reject等)
先上一段使用代碼 兩個(gè).then

在最后的console.log打斷點(diǎn) 看到的堆棧是這樣的

二十幾個(gè)啊 咳咳 看看多少同名的玩意....
在promise.js中加了一些有意義的輸出 控制臺(tái)是這樣的(圖三)

這里聲明:
①②③④⑤⑥⑦⑧⑨⑩...為標(biāo)記 可以通過標(biāo)記符在很多行的文字解釋和代碼之間查找 沒辦法 promise里各種同名不同棧的函數(shù)..
上promise.js源碼(使用的是https://blog.csdn.net/qq_22844483/article/details/73655738 里的部分代碼 轉(zhuǎn)載未申請 好開心)
<pre>
var i = 0;
function Promisee(fn) {
? ? var state = 'pending',
? ? ? ? value = null,
? ? ? ? callbacks = [],
? ? ? ? aa = ++i; ②
? Promisee.ii = i, ①
? ? this.then = function thenFun(onFulfilled) {
? ? ? ? return new Promisee(function resolveFuc(resolve) {
? ? ? ? ? ? handle({
? ? ? ? ? ? ? ? onFulfilled: onFulfilled || null,
? ? ? ? ? ? ? ? resolve: resolve
? ? ? ? ? ? });
? ? ? ? });
? ? };
? ? function handle(callback) {
? ? ? ? if (state === 'pending') {
? ? ? ? ? ? callbacks.push(callback);
? ? ? ? ? ? console.log('狀態(tài)是pending',"這是Promisee第",handle.caller.caller.ii,"次執(zhí)行時(shí)執(zhí)行的handle方法 當(dāng)然 handle是在Promisee第", aa,"次定義的");//說明調(diào)用handle的是this.then中的Promisee
? ? ? ? ? ? console.log('push', callbacks);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //如果then中沒有傳遞任何東西
? ? ? ? if(!callback.onFulfilled) {
? ? ? ? ? ? callback.resolve(value);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? console.log('狀態(tài)是fulfilled','這是第',aa,'個(gè)Promisee里的handle');
? ? ? ? var ret = callback.onFulfilled(value); ⑨
? ? ? ? callback.resolve(ret);
? ? }
? ? function resolve(newValue) {
? ? ? ? console.log('這是第',aa,'個(gè)Promisee里的resolve');
? ? ? ? if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
? ? ? ? ? ? var then = newValue.then;
? ? ? ? ? ? if (typeof then === 'function') {
? ? ? ? ? ? ? ? then.call(newValue, resolve);
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(newValue == undefined){
? ? ? ? ? ? console.log('\tvalue等于undefined了 還是在resolve內(nèi)執(zhí)行');
? ? ? ? ? ? if(callbacks.length == 0)
? ? ? ? ? ? ? ? console.log('\t啥都木有');
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? state = 'fulfilled';
? ? ? ? value = newValue;
? ? ? ? setTimeout(function setTimeoutFuc() {
? ? ? ? ? ? callbacks.forEach(function (callback) {
? ? ? ? ? ? console.log('pop', callbacks);
? ? ? ? ? ? handle(callback);
? ? ? ? ? ? });
? ? ? ? }, 0);
? ? }
? ? fn(resolve); ⑥
}
</pre>
對照執(zhí)行代碼看下
<pre>
var a = function(){
return new Promisee(function(resolve, reject){
setTimeout(function(){
resolve(1);
},100);
})
}
a().then(function(num){ ③
return new Promisee(function(resolve){
setTimeout(function(){
console.log('這是第二個(gè)setTimeout方法 已經(jīng)開始執(zhí)行');
resolve(num*3);
},100)
})
})
.then(function(num2){ ⑤
console.log('num2',num2);
})
</pre>
Promise.js源碼中很重要的一條語句就是最后的fn(resolve) [標(biāo)記6] 這條語句可以讓帶有參數(shù)的Promise在實(shí)例化時(shí)自動(dòng)執(zhí)行他的參數(shù) 同時(shí)把resolve傳入 注意 這里的resolve如果是then的參數(shù)的參數(shù) 那往往是Promise的上層堆棧的resolve 這個(gè)可以從圖三里很好的看出來 而最重要的所謂反轉(zhuǎn)的反轉(zhuǎn)的實(shí)現(xiàn) 就在這里! 通過handle函數(shù) 利用詞法作用域 將本層堆棧的對象push到上層callbacks中 以實(shí)現(xiàn)不同promise的通信
[標(biāo)記1]這里是我自己標(biāo)記的針對不同promise做的ii屬性 這樣可以在函數(shù)調(diào)用時(shí) 查看它是在哪個(gè)promise調(diào)用的
[標(biāo)記2]這個(gè)就有趣了 可以用來跟蹤所謂通過在函數(shù)promise中添加私有屬性i 在調(diào)用resolve和handle時(shí) 可以同時(shí)打印resolve和handle所在詞法作用域的i屬性 從而顯示這兩個(gè)函數(shù)是哪個(gè)
堆棧調(diào)用的^^
開始看代碼(圖三結(jié)合圖二)
首先[標(biāo)記3] a()執(zhí)行返回promise[這是第一個(gè)promise] 繼續(xù)調(diào)用.then 會(huì)繼續(xù)返回promise[第二個(gè)promise]同時(shí)在then中的function會(huì)作為onFulfilled作為后續(xù)處理 其實(shí)就是通過第二個(gè)promise的handle方法(這個(gè)handle其實(shí)是第一個(gè)promise的) 將onFulfilled和第二個(gè)promise的resolve push到第一個(gè)promise的callbacks中(這里很重要!!!!!!做標(biāo)記④ handle沒有傳參 所以是從上級(jí)的堆棧調(diào)用 而resolve是傳參了 那直接從函數(shù)作用域調(diào)用 故是屬于當(dāng)前promise的resolve) 從圖三的第一行可以看到

代碼往下走 到達(dá)第二個(gè)then [標(biāo)記5] then返回一個(gè)promise(第三個(gè)promise) 同時(shí)then的參數(shù)同樣作為onFulfilled 和 第三個(gè)promise的resolve 進(jìn)入handle函數(shù)push到第二個(gè)promise中 從圖三的第三四行可以看到

代碼往下走 代碼沒了..
回過頭 在剛剛的a()執(zhí)行時(shí) 不僅返回了promise 而且通過promise的最后一行代碼fn(resolve)[標(biāo)記6]執(zhí)行了
<pre>
function(resolve, reject){
? ? ? ? ? ? setTimeout(function(){
? ? ? ? ? ? ? ? resolve(1);
? ? ? ? ? ? },100);
</pre>
這塊的代碼 這個(gè)函數(shù)的執(zhí)行 會(huì)執(zhí)行setTimeout 進(jìn)行隊(duì)列排隊(duì)(意思就是如果有其他代碼執(zhí)行就先執(zhí)行下面的代碼 如果下面的代碼有setTimeout就接著這個(gè)setTimeout排隊(duì) 如果沒有其他代碼執(zhí)行了就開始從頭執(zhí)行setTimeout) 然而在執(zhí)行完兩個(gè)then后 回過頭來開始要執(zhí)行這個(gè)setTimeout了 因?yàn)槠渌a都執(zhí)行完了 promise.js里面的不是執(zhí)行代碼 圖一的才是 ok
好的 這個(gè)倒序整的..
現(xiàn)在setTimeout執(zhí)行了 等待100毫秒后(這個(gè)100毫秒其實(shí)是從注冊了setTimeout就開始算起的) 開始執(zhí)行resolve(1); 這個(gè)resolve是第幾個(gè)promise的resolove? 第一個(gè)! 因?yàn)橐簧蟻砭蛨?zhí)行"a()" 而a里面就是很單純的將promise.js里倒數(shù)27行的resolve傳到了最后的fn(resolve)里(或者說最后的fn(resolve)里的resolve就是promise.js里倒數(shù)第27行的resolve) ok? 真是 太單純了 再也找不到這么單純的了 好難的 555.. 從圖三的第5行也可以看到? ? ? ? ?

現(xiàn)在開始執(zhí)行resolve了 也就是下面的這塊代碼 在上面的代碼塊中可以找到
<pre>
? ? ? ? state = 'fulfilled';
? ? ? ? value = newValue;
? ? ? ? setTimeout(function setTimeoutFuc() {
? ? ? ? ? ? callbacks.forEach(function (callback) {
? ? ? ? ? ? ? ? console.log('pop', callbacks);? ? //? <<== 這里很有愛
? ? ? ? ? ? ? ? handle(callback);
? ? ? ? ? ? });
? ? ? ? }, 0);
</pre>
狀態(tài)(state)被改變成了fulfilled 然后開始setTimeout隊(duì)列 問題現(xiàn)在其他代碼都執(zhí)行完了 setTimeout直接開始執(zhí)行了 這里面的callbacks是第幾個(gè)promise的呢 答案是第一個(gè) 因?yàn)閞esolve是第一個(gè)promise的
而第一個(gè)promise的resolve只能找到第一個(gè)promise里的數(shù)據(jù) 如果是第二個(gè)promise的resolve 或者h(yuǎn)andle就可以訪問第二個(gè)promise或者第一個(gè)promise的數(shù)據(jù) 這是作用域的概念 ok
至于callbacks里面的數(shù)據(jù) 實(shí)際上是第一個(gè)then里面的handle push到第一個(gè)promise的callbacks里面的數(shù)據(jù) 由于在promise.js里寫了"console.log('pop', callbacks);"這條語句 所以控制臺(tái)的第六行顯示

然后 handle開始處理這個(gè)callback 也就是一個(gè)對象啦
(((((((((((((((((((((((((((各單位注意 高潮開始了))))))))))))))))))))))))))))))
進(jìn)入handle 現(xiàn)在的堆棧是第一個(gè)promise 而之前進(jìn)行push時(shí)[標(biāo)記4]handle用的是第一個(gè)promise的handle 因?yàn)樽鳛閠hen的參數(shù)中的handle也只能用第一個(gè)promise的傳入啊 handle代碼如下
<pre>
? ? function handle(callback) {
? ? ? ? if (state === 'pending') {
? ? ? ? ? ? callbacks.push(callback);
? ? ? ? ? ? console.log('狀態(tài)是pending',"這是Promisee第",handle.caller.caller.ii,"次執(zhí)行時(shí)執(zhí)行的handle方法 當(dāng)然 handle是在Promisee第", aa,"次定義的");//說明調(diào)用handle的是this.then中的Promisee
? ? ? ? ? ? console.log('push', callbacks);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //如果then中沒有傳遞任何東西
? ? ? ? if(!callback.onFulfilled) {
? ? ? ? ? ? callback.resolve(value);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? console.log('狀態(tài)是fulfilled','這是第',aa,'個(gè)Promisee里的handle');
? ? ? ? var ret = callback.onFulfilled(value);
? ? ? ? callback.resolve(ret);
? ? }
</pre>
現(xiàn)在進(jìn)入(第一個(gè)promise的)handle函數(shù) 由于狀態(tài)(第一個(gè)promise的state)已經(jīng)改為fulfilled 故直接執(zhí)行callback.onFulfilled(value); value即是第一個(gè)執(zhí)行的resolve傳入的參數(shù)1 onFulfilled是then傳入的函數(shù)參數(shù)
function(num){
return new Promisee(function(resolve){
setTimeout(function(){ ⑧
console.log('這是第二個(gè)setTimeout方法 已經(jīng)開始執(zhí)行');
resolve(num*3);
},100)
})
}
執(zhí)行后 返回第四個(gè)promise 注意 此時(shí)會(huì)同時(shí)執(zhí)行此promise的參數(shù) 可參考[標(biāo)記6] 執(zhí)行setTimeout方法 結(jié)果就是列入隊(duì)列 此時(shí)setTimeout內(nèi)的的resolve為第四個(gè)promise的resolve
下一句非常重要
`
callback.resolve(ret);
`
這個(gè)callback里的resolve是第幾個(gè)promise的resolve? 看[標(biāo)記4] 是第二個(gè)promise的resolve!看真相圖

而ret是第四個(gè)promise 好的 開始愉快的執(zhí)行resolve吧
<pre>
function resolve(newValue) {
? ? ? ? console.log('這是第',aa,'個(gè)Promisee里的resolve');
? ? ? ? if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
? ? ? ? ? ? var then = newValue.then;
? ? ? ? ? ? if (typeof then === 'function') {
? ? ? ? ? ? ? ? then.call(newValue, resolve);
? ? ? ? ? ? ? ? return; ⑦
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if(newValue == undefined){
? ? ? ? ? ? console.log('\tvalue等于undefined了 還是在resolve內(nèi)執(zhí)行');
? ? ? ? ? ? if(callbacks.length == 0)
? ? ? ? ? ? ? ? console.log('\t啥都木有');
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? state = 'fulfilled';
? ? ? ? value = newValue;
? ? ? ? setTimeout(function setTimeoutFuc() {
? ? ? ? ? ? callbacks.forEach(function (callback) {
? ? ? ? ? ? console.log('pop', callbacks);
? ? ? ? ? ? handle(callback);
? ? ? ? ? ? });
? ? ? ? }, 0);
? ? }
</pre>
由于ret 也就是這里傳進(jìn)來的newValue是一個(gè)promise 進(jìn)入第一個(gè)if 來回來去執(zhí)行到了
`then.call(newValue, resolve);`
言外之意是 "我要執(zhí)行第四個(gè)promise的then方法哦 而且是把第二個(gè)resolve傳進(jìn)去作為onFulfilled哦"
這句代碼實(shí)在是太經(jīng)典了 因?yàn)橹髸?huì)重用第二個(gè)resolve!
好的 then執(zhí)行了 返回了第五個(gè)promise!

<pre>
this.then = function thenFun(onFulfilled) {
? ? ? ? return new Promisee(function resolveFuc(resolve) {
? ? ? ? ? ? handle({
? ? ? ? ? ? ? ? onFulfilled: onFulfilled || null,
? ? ? ? ? ? ? ? resolve: resolve
? ? ? ? ? ? });
? ? ? ? });
? ? };
</pre>①②③④⑤⑥⑦⑧⑨⑩
通過第四個(gè)promise的handle(不要問我為什么是第四個(gè) 因?yàn)槊總€(gè)then的參數(shù)調(diào)用都只能通過作用于向上找到上級(jí)promise的handle啊 因?yàn)閰?shù)沒傳handle啊 ( ˇ?ˇ )) 把第二個(gè)resolve(即這里的onFulfilled)和第五個(gè)resolve(第五個(gè) wtf!)push到了第四個(gè)promise中
注意上面的[標(biāo)記7] 這里有個(gè)return 按時(shí)一切的push到此結(jié)束了...
回到[標(biāo)記8]的setTimeout 開始執(zhí)行隊(duì)列
`resolve(num*3)`
第四個(gè)resolve開始執(zhí)行 通過閉包向上找到num 也就是[標(biāo)記9]的value

此時(shí)的數(shù)字已經(jīng)通過num*3 也就是1*3 得到了數(shù)字3
然后 把第四個(gè)promise中的callbacks逐個(gè)用handle處理了 callbacks里有什么 當(dāng)然是上面幾行里剛剛push的第二個(gè)promise的resolve和第五個(gè)promise的resolve
執(zhí)行第二個(gè)promise的resolve:
`var ret = callback.onFulfilled(value);`
由于resolve里是一個(gè)setTimeout 這樣開始隊(duì)列
再執(zhí)行下一句
`callback.resolve(ret);`
這個(gè)resolve是第五個(gè)resolve 開始執(zhí)行 可是第五個(gè)promise里面啥也木有
回頭開始執(zhí)行隊(duì)列
<pre>
setTimeout(function setTimeoutFuc() {
? ? ? ? ? ? callbacks.forEach(function (callback) {
? ? ? ? ? ? console.log('pop', callbacks);
? ? ? ? ? ? handle(callback);
? ? ? ? ? ? });
? ? ? ? }, 0);
</pre>
第二個(gè)resolve講第二個(gè)promise的callbacks數(shù)組 也就是代碼階段第二個(gè)then執(zhí)行push的函數(shù) 調(diào)出來執(zhí)行
<pre>
.then(function(num2){
console.log('num2',num2);
})
</pre>
重復(fù)的handle代碼我就不再貼了
兩句重要的如下
`var ret = callback.onFulfilled(value);
? ? ? ? callback.resolve(ret);`
第一句是把
`function(num2){
console.log('num2',num2);
}`
執(zhí)行 此處的value就是剛才(num*3)得到的 通過閉包獲得
這樣控制臺(tái)打印出'num2' 3

還沒有結(jié)束 各位老板
還有一句沒有執(zhí)行完
`callback.resolve(ret)`
此時(shí)ret是console.log的返回值 即undefined 即使進(jìn)入resolve也是沒有意義的 因?yàn)榈谌齻€(gè)promise里沒有壓入如何的對象(即沒有執(zhí)行handle) 第三個(gè)promise是在哪生成的呢? 大家想想 答案就是執(zhí)行代碼的第二個(gè)then 因?yàn)閠hen后沒有then了 所以也就沒有執(zhí)行那個(gè)沒有的then里面的handle 也就是說如果繼續(xù)有then就繼續(xù)handle繼續(xù)push繼續(xù)扯 扯 扯 扯到世界末日( ⊙ o ⊙ )啊!

可以了 完結(jié)撒花.