实现一个符合promiseA+规范的promise
实现promiseA+规范时有几个思考点值得注意:
- then方法的作用是什么?
then(succeed, failed)内部其实就是将succeed和failed这两个处理成功和失败的回调函数和then执行后生成的新promise对象push进callbacks[] 这个数组里。 - 如何让then方法返回一个promise(实现链式调用)?
在callbacks里找到成功或失败的回调,call调用他们,记录结果然后在生成的新promise里手动resolve这个结果。 - then(succeed, failed) 中的succeed和failed有返回值x,x可能是哪些值?分别该作何处理?如果在succeed和failed执行时出现了异常该如何处理?
具体说明在promiseA+规范的2.3章节。x可能是promise对象自身,可能是一个新的promise对象,或者一个对象,一个函数,一个thenable,或者其他简单类型。 - 如何模拟一个微任务?
settimeout是宏任务,而then则是微任务,在node环境可以使用process.nextTick(),而在浏览器环境则使用MutationObserver来代替。
这些问题其实在promiseA+规范中已经讲清楚了,所以只要按照规范写出测试用例,进而写出满足测试用例的代码,就实现了一个符合规范的Promise。
export default class Promise2 {
state='pending'
callbacks = []
resolve(result) {
this.excute('fulfilled', result, 0)
}
reject(reason) {
this.excute('rejected', reason, 1)
}
excute(state, data, i) {
if(this.state !== 'pending') return
this.state = state
nextTick(() => {
this.callbacks.forEach(el => {
if(typeof el[i] === 'function') {
let x
try {
x = el[i].call(undefined, data)
} catch (error) {
el[2].reject(error)
}
el[2].resolveWith(x)
}
})
})
}
constructor(fn) {
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, failed?) {
const arr = []
if(typeof succeed === 'function') {
arr[0] = succeed
}
if(typeof failed === 'function') {
arr[1] = failed
}
arr[2] = new Promise2(() => {})
this.callbacks.push(arr)
return arr[2]
}
resolveWithThenable(x) {
try {
x.then(
y => {
this.resolveWith(y);
},
r => {
this.reject(r);
}
);
} catch (e) {
this.reject(e);
}
}
resolveWith(x) {
if (this === x) this.reject(new TypeError())
else if (x instanceof Promise2) {
x.then(res => {
this.resolve(res)
}, err => {
this.reject(err)
})
} else if (x instanceof Object) {
// if a thenable
let then
try {
then = x.then
} catch(e) {
this.reject(e)
}
if (then instanceof Function) {
this.resolveWithThenable(x)
} else {
this.resolve(x)
}
} else {
this.resolve(x)
}
}
}
function nextTick(fn) {
if(process !== undefined && typeof process.nextTick === 'function')
return process.nextTick(fn)
else {
var counter = 1
var observer = new MutationObserver(fn)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
counter = counter+1
textNode.data = String(counter)
}
}

浙公网安备 33010602011771号