實現一個Promise


實現一個Promise

說到Promise,我們首先想到的最核心的功能就是異步鏈式調用,本篇文章就帶你用20行代碼實現一個可以異步鏈式調用的Promise。

這個Promise的實現不考慮任何異常情況,只考慮代碼最簡短,從而便於讀者理解核心的異步鏈式調用原理。

代碼

先給代碼吧,真就20行。

<code>function Promise(excutor) {
var self = this
self.onResolvedCallback = []
function resolve(value) {
setTimeout(() => {
self.data = value
self.onResolvedCallback.forEach(callback => callback(value))
})
}
excutor(resolve.bind(self))
}
Promise.prototype.then = function(onResolved) {
var self = this
returnnewPromise(resolve => {
self.onResolvedCallback.push(function() {
var result = onResolved(self.data)
if (result instanceofPromise) {
result.then(resolve)
} else {
resolve(result)
}
})
})
}/<code>

核心案例

<code>newPromise(resolve => {
setTimeout(() => {

resolve(1)
}, 500)
})
.then(res => {
console.log(res)
returnnewPromise(resolve => {
setTimeout(() => {
resolve(2)
}, 500)
})
})
.then(console.log)/<code>

本文將圍繞這個最核心的案例來講,這段代碼的表現如下:

  1. 500ms後輸出1
  2. 500ms後輸出2

實現

構造函數

首先來實現Promise構造函數

<code>function Promise(excutor) {
var self = this
self.onResolvedCallback = [] // Promise resolve時的回調函數集

// 傳遞給Promise處理函數的resolve
// 這裡直接往實例上掛個data
// 然後把onResolvedCallback數組裡的函數依次執行一遍就可以
function resolve(value) {
// 注意promise的then函數需要異步執行
setTimeout(() => {
self.data = value
self.onResolvedCallback.forEach(callback => callback(value))
})

}

// 執行用戶傳入的函數
excutor(resolve.bind(self))
}/<code>

好,寫到這裡先回過頭來看案例

<code>const excutor = resolve => {
setTimeout(() => {
resolve(1)
}, 500)
}

newPromise(excutor)/<code>

分開來看,excutor就是用戶傳的函數,這個函數內部調用了resolve函數後,就會把promise實例上的onResolvedCallback執行一遍。

到此為止我們還不知道onResolvedCallback這個數組裡的函數是從哪裡來的,接著往下看。

then

這裡是最重要的then實現,鏈式調用全靠它:

<code>Promise.prototype.then = function(onResolved) {
// 保存上下文,哪個promise調用的then,就指向哪個promise。
var self = this

// 一定要返回一個新的promise
// promise2
returnnewPromise(resolve => {
self.onResolvedCallback.push(function() {
var result = onResolved(self.data)
if (result instanceofPromise) {
// resolve的權力被交給了user promise
result.then(resolve)

} else {
resolve(result)
}
})
})
}/<code>

再回到案例裡

<code>var excutor = resolve => {
setTimeout(() => {
resolve(1)
}, 500)
}

var promise1 = newPromise(excutor)

promise1.then(res => {
console.log(res)
// user promise
returnnewPromise(resolve => {
setTimeout(() => {
resolve(2)
}, 500)
})
})/<code>

注意這裡的命名:

  1. 我們把Promise構造函數返回的實例叫做promise1,
  2. 在then的實現中,我們構造了一個新的promise返回,叫它promise2
  3. 在用戶調用then方法的時候,用戶手動構造了一個promise用來做異步的操作,叫它user promise

那麼在then的實現中,self其實就指向promise1

而promise2的excutor中,立刻執行了一個函數,它往promise1的onResolvedCallback數組中push了一個函數,

那麼重點看這個push的函數,注意,這個函數在promise1被resolve了以後才會執行。

<code>self.onResolvedCallback.push(function() {
// onResolved就對應then傳入的函數
var result = onResolved(self.data)
// 例子中的情況 返回了一個promise3
if (result instanceofPromise) {
// 那麼直接把promise2的resolve決定權交給了user promise
result.then(resolve)
} else {
resolve(result)
}
})/<code>

如果用戶傳入給then的onResolved方法返回的是個promise,那麼這個user promise裡拿到的參數resolve,其實就指向了內部promise2的resolve,

所以這就可以做到:user promise被resolve以後,then2函數才會繼續執行,

<code>newPromise(resolve => {
setTimeout(() => {
// resolve1
resolve(1)
}, 500)
})
// then1
.then(res => {
console.log(res)
// user promise
returnnewPromise(resolve => {
setTimeout(() => {
// resolve2
resolve(2)
}, 500)
})
})
// then2
.then(console.log)/<code>

then1其實進入了promise1的回調數組裡,所以resolve1執行完畢後,then1才會執行

then2其實進入了promise2的回調數組裡,又因為我們剛剛知道,resolve2正是promise2的resolve方法,

所以resolve2執行完畢後, then2才會執行,這就實現了異步的鏈式調用。

要點總結

一個核心的要點:

  1. 簡單情況 then1函數是個同步函數,返回一個普通的值。then1裡傳入的函數,其實是被放到promise1的回調數組裡,
<code>// promise1
newPromise(resolve => {
setTimeout(resolve, 1000)
})
// then1 這裡傳入的函數 會被放到調用者promise的回調數組中
.then(res => {
console.log(res)
})/<code>

這樣的話,1秒後,promise1被resolve了,是不是then1裡的函數就被執行了呢~

  1. 複雜情況 then函數返回了個promise 如果這個then函數里返回了一個promise,那麼這個返回的promise內部的resolve,其實就指向
<code>// 調用then的promise
newPromise(resolve => {
setTimeout(resolve, 1000)
})
// then2
.then(res => {
// user promise
returnnewPromise(resolve => {
setTimeout(resolve, 1000)
})
})
// then3
.then(res => {
console.log(res)
})/<code>

then2會返回promise2(注意不是user promise,而是源碼內部返回的那個promise2),

then3傳入的函數會被放到promise2的回調數組裡。

由於then2中用戶自己返回了一個user promise,

所以promise2的resolve權力會被交給user promise,

在1秒後,user promise被resolve了,那麼代表著promise2被reoslve了,那麼在promise2的回調數組裡會找到then3傳入的回調函數

它就被完美的執行了。


分享到:


相關文章: