promise是用來解決瘋狂地獄式回撥函式的問題,多種巢狀回撥函式的方式不利於程式碼的維護,於是是否可以讓回撥函式不用巢狀,按照同步的方式來寫
先看一段promise函式的簡單程式碼的應用:
new Promise(function(resolve, reject) {
console.log('init');
resolve('then1');
}).then(function(val) {
console.log(val);
return "then2";
}).then(function(val) {
console.log(val);
})
結果:
init
then1
then2
複製程式碼
分析:
1.根據promise的建構函式來看,只有呼叫resolve方法後,才會執行then後面的函式
2.then方法可以鏈式呼叫,上一層的then函式返回值可以傳給下一層的函式then的引數
猜想:
當呼叫resolve方法後,then後面的函式是依次執行的,then函式可能是會將傳入的函式引數儲存到內部陣列去,但是為了確保在resolve之後,then所有的函式引數都已經儲存起來,resolve方法執行順序可能是非同步的;可能還會存在一個儲存then函式之間傳遞的內部引數值。
下面寫個簡單例項來探究:
function MPromise(fn) {
this.thenCb = [];
this.state = null;
this.value = null;
fn(this.resolve, this.reject, this);
}
MPromise.prototype.then = function(onResolve, onReject) {
this.thenCb.push(onResolve);
return this;
}
MPromise.prototype.resolve = function(_value, self) {
setTimeout(() => {
self.value = _value;
for (var i = 0; i < self.thenCb.length; i++) {
self.value = self.thenCb[i](self.value);
}
}, 0);
}
var p = new MPromise((resolve, reject, self) => {
console.log('init');
resolve('then1', self);
}).then(val => {
console.log(val);
return 'then2'
}).then(val => {
console.log(val);
});
結果:
init
then1
then2
複製程式碼
似乎這個已經可以實現當前的功能了。細究一下resolve方法必須是非同步的,否則還沒等到將then方法的函式引數儲存起來就已經呼叫了,那麼如何實現非同步呢?
setTimeout;setImmediate;Process.nextTick
setImmediate和Process.nextTick的區別
A(); B(); C(); ------------------------------------------------------------------------A(); process.nextTick(B); C(); ------------------------------------------------------------------------A(); setImmediate(B); C();
process.nextTick:在本輪迴圈結束後立刻執行,相當於微任務
setImmediate:在次輪迴圈開始最後才執行,相當於巨集任務
參考:事件迴圈佇列
所以一般在低版本ie8瀏覽器下,選擇使用setTimeout來實現非同步。
言歸正傳:知道如何實現非同步之後,如果then函式返回是一個新的promise,該如何區分執行
promise原始碼中
// States:
//
// 0 - pending
// 1 - fulfilled with _value
// 2 - rejected with _value
// 3 - adopted the state of another promise, _value
//
// once the state is no longer pending (0) it is immutable
複製程式碼
promise狀態一旦改變就不可以更改,並且只允許從0 -> 1/2/3,界定每個promise的狀態值來解決
還有reject, catch, promise.all, promise.race如何實現,下次更新。