whynotgonow 2020-05-16
const PENDING = ‘pending‘
const FULFILLED = ‘fulfilled‘
const REJECTED = ‘rejected‘
function MyPromise(executor) {
let self = this
self.value = null
self.error = null
self.status = PENDING
// 异步 readFile 尚未 resolve 的时候先存储所有成功回调。
// 即 thenable 方法中 status = PENDING 的时候先存储。
// 待异步 readFile 执行到 resolve 时,status 改变然后依次执行 onFulfilledCallbacks 中的回调函数。
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
const resolve = (value) => {
if (self.status !== PENDING) return; // res 或 rej 只走一条路径
setTimeout(() => {
self.status = FULFILLED
self.value = value
self.onFulfilledCallbacks.forEach((callback) => callback(self.value)) // 异步逻辑执行回调
})
}
const reject = (error) => {
if (self.status !== PENDING) return; // res 或 rej 只走一条路径
setTimeout(() => {
self.status = REJECTED
self.error = error
self.onRejectedCallbacks.forEach((callback) => callback(self.error)) // promise异步任务
})
}
executor(resolve, reject)
}
// then 函数整体是一个同步进行的状态,遇到异步任务时,只有 this.status = PENDING
MyPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === ‘function‘ ? onFulfilled : value => value
onRejected = typeof onRejected === ‘function‘ ? onRejected : error => { throw error }
let bridgePromise;
let self = this;
// PENDING 时同步存储进回调数组 callbacks
// 异步 readFile 时走 PENDING,因为同步执行到 then 时,readFile 尚未 resolve
if (self.status === PENDING) {
// return promise 可以放在 if else 的最层
return bridgePromise = new MyPromise((resolve, reject) => { // new promise 立即执行
self.onFulfilledCallbacks.push((value) => {
try {
let x = onFulfilled(value) // 拿到 then 中回调返回的结果?
resolvePromise(bridgePromise, x, resolve, reject); // x 可能还是 promise
} catch (e) {
reject(e)
}
})
self.onRejectedCallbacks.push((error) => {
try {
let x = onRejected(error);
// 假若 x 还是一个 promise,不能直接 resolve
resolve(x);
} catch (e) {
reject(e);
}
});
})
} else if (this.status === FULFILLED) { // 同步执行走到 FULFILLED
return bridgePromise = new MyPromise((resolve, reject) => {
try {
let x = onFulfilled(self.value)
resolvePromise(bridgePromise, x, resolve, reject)
} catch (e) {
reject(e)
}
})
} else {
return bridgePromise = new MyPromise((resolve, reject) => {
try {
let x = onRejected(self.error)
resolvePromise(bridgePromise, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
}
MyPromise.prototype.catch = function (onRejected) {
return this.then(null, onRejected)
}
// finally 本质上是一个 then 方法
// 入参 callback 是一个函数,需要在 then 中执行
// 使用 Promise.resolve 会等 callback() 函数执行完后再返回结果,并将上一个 then 的 value 返回
MyPromise.prototype.finally = function (callback) {
// this 即上一个 promise
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, error => {
return MyPromise.resolve(callback()).then(() => {
throw error;
})
})
}
MyPromise.resolve = function (callback) {
// MyPromise.resolve 的职责就是返回一个 promise 对象,显然已经达到,故直接返回
if (callback instanceof MyPromise) return callback;
return new MyPromise((resolve, reject) => {
if (callback.then && typeof callback.then === ‘function‘) {
callback.then(resolve, reject)
} else {
resolve(callback)
}
})
}
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
let len = promises.length
let result = []
let index = 0
if (len === 0) return resolve(resutl);
for (let i = 0; i < len; i++) {
// 统一转成 promise 对象处理
MyPromise.resolve(promises[i]).then(res => {
result[i] = res
index++;
if (index === len) resolve(result);
}).catch(err => {
reject(err);
})
}
})
}
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
let len = promises.length
if (len === 0) return;
for (let i = 0; i < len; i++) {
MyPromise.resolve(promises[i]).then(data => {
resolve(data)
return;
}).catch(err => {
reject(err)
return;
})
}
})
}
function resolvePromise(bridgePromise, x, resolve, reject) {
if (x instanceof MyPromise) {
if (x.status === PENDING) {
x.then(y => {
resolvePromise(bridgePromise, y, resolve, reject)
}, error => {
reject(error)
})
} else {
x.then(resolve, reject)
}
} else {
resolve(x)
}
}
let fs = require(‘fs‘)
let readFilePromise = (filename) => {
return new MyPromise((resolve, reject) => {
fs.readFile(filename, (err, data) => {
if (!err) {
resolve(data)
} else {
reject(err)
}
})
})
}
readFilePromise(‘./p6.html‘).then(data => {
console.log(‘1_p6.html‘)
return readFilePromise(‘./p6.html‘)
}).then(data => {
console.log(‘2_p6.html‘)
})