问题导向
手写promise,了解promise内部原理
如果你都有了答案,可以忽略本文章,或去JS学习地图寻找更多答案
代码如下
;(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function Promise(excutor) {
let self = this
self.status = PENDING
self.data = undefined
self.callbacks = []
//立即同步执行excutor
//当抛出异常时,执行失败处理回调
try {
excutor(resolve, reject)
} catch (error) {
reject(error)
}
function resolve(value) {
//如果当前状态不是pending,不执行
if (self.status !== PENDING) {
return
}
console.log(this)
//当执行resolve时,要做3件事:
//1.将状态改为resolved
self.status = RESOLVED
//2.保存value数据
self.data = value
//3.如果有待执行callback,立即异步执行回调函数onResolved
if (self.callbacks.length > 0) {
//模拟微队列
setTimeout(() => {
self.callbacks.forEach((callbacksObj) => {
callbacksObj.onResolved(value)
})
})
}
}
function reject(reason) {
if (self.status !== PENDING) {
return
}
console.log(this)
self.status = REJECTED
self.data = reason
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach((callbacksObj) => {
callbacksObj.onRejected(reason)
})
})
}
}
}
//指定成功和失败的回调函数,返回一个新的promise对象
Promise.prototype.then = function (onResolved, onRejected) {
//指向回调的默认值(必须是函数)
//向后传递成功的value
onResolved =
typeof onResolved === 'function' ? onResolved : (value) => value
//实现异常穿透的代码
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
let self = this
/*返回一个新的promise对象,而且新的promise对象可能会调用resolve或者reject,
而调用哪个取决onResolved或者onRejected执行的结果*/
return new Promise((resolve, reject) => {
//调用指定的回调函数处理,根据执行的结果改变return的promise状态
//因为内部要调用resolve/reject,只能定义在Promise内部
function handle(callback) {
//处理多种情况:
//1.如果抛出异常
//2.如果回调函数返回非promise
//3.回调函数返回promise
//为了捕获异常,使用try catch
try {
//如果是成功回调,获取返回值,用于判断
const result = callback(self.data)
//3.返回非promise
if (result instanceof Promise) {
//难点:看不见的代码,原型链知识:
//因为返回了一个new Promise,所以每个实例都可以调用原型方法then
//只有then才能知道它返回的结果
// result.then(
// (value) => resolve(value), //当result成功时,让新的promise也成功
// (reason) => reject(reason) //当result失败时,让新的promise也失败
// )
//简洁版:
result.then(resolve, reject)
/*
如同:
function fn(){}
div.onclick = function(e){ fn(e) }
div.onclick = fn //两种等价,这个效率更高
*/
} else {
resolve(result) //2.返回非promise
}
} catch (error) {
reject(error) //1.如果抛出异常
}
}
//如果是pending态,把回调存起来,以便调用
if (self.status === PENDING) {
self.callbacks.push({
//因为外面已经包了定时器了,所以这里不再需要了
//pending的状态(待调用),其实也要做同样的事情
onResolved() {
handle(onResolved)
},
onRejected() {
handle(onRejected)
},
})
//如果是resolved态,需要异步执行onResolved,并改变return的promise状态
} else if (self.status === RESOLVED) {
// 回调函数是异步的
setTimeout(() => {
handle(onResolved)
})
} else {
//如果是rejected态
setTimeout(() => {
handle(onRejected)
})
}
})
}
//指定失败的回调函数,返回一个promise对象
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
//返回一个成功或失败的promise
/*
用法:
const p1 = Promise.resolve('1') 如果是普通值,就走成功
const p2 = Promise.resolve(Promise.resolve('2'))如果是成功promise
const p3 = Promise.resolve(Promise.reject('3'))如果是失败promise
*/
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
//value是promise
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
//value不是promise
resolve(value)
}
})
}
//返回一个指定reason必定是失败的promise
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
//返回一个promise,所有promise都成功才成功
//难点:怎么知道都成功了?
//解决:计数与条件函数
Promise.all = function (promiseArr) {
// const result = new Array(promiseArr.length)
const success = []
const fail = []
let resolvedCount = 0 //用于计算是否全部成功
return new Promise((resolve, reject) => {
promiseArr.forEach((p, index) => {
// 包一层的写法:Promise.resolve(p).then(),如果数组中不是传promise,照样可以得到promise
p.then(
(value) => {
resolvedCount++
success[index] = value
// if (resolvedCount === promiseArr.length) {
// resolve(success)
// }
},
(reason) => {
fail[index] = reason
reject({ index: index, data: reason }) //rejected状态只会进入一次
}
)
})
resolve({ success, fail })
})
}
//返回一个promise,谁最快就返回谁,无论成功还是失败
//难点:怎么知道谁最快?
//解决:遍历 + 利用状态只会改变一次的特点
Promise.race = function (promiseArr) {
return new Promise((resolve, reject) => {
//返回一个最快的值,需要遍历,才能知道谁最快
promiseArr.forEach((p, index) => {
p.then(
(value) => {
resolve(value)
},
(reason) => {
reject(reason)
}
)
})
})
}
//只返回最快返回的成功的值
Promise.race_success = function (promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach((p, index) => {
p.then((value) => {
resolve(value)
})
})
})
}
Promise.resolveDelay = function (value, await) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
}, await)
})
}
window.Promise = Promise
})(window)
学习更多