手写promise的过程是按照promise A+标准,先写测试用例,然后测试驱动开发,开发一个满足测试用例的promise。
class Promise2 {
state = "pending";
callbacks = [];
resolve(result) {
if (this.state !== 'pending') return
this.state = 'fulfilled'
nextTick(() => {
this.callbacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
handle[0].call(undefined,result)
}
})
})
}
reject(reason) {
if (this.state !== 'pending') return
this.state = 'rejected'
nextTick(() => {
this.callbacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
handle[1].call(undefined,reason)
}
})
})
}
constructor(fn) {
if(typeof fn != 'function'){
throw new Error('Promise必须传入一个函数类型的参数')
}
fn(this.resolve.bind(this),this.reject.bind(this))
}
then(succeed?, fail?) {
const handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
this.callbacks.push(handle)
}
}
export default Promise2;
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);
}
}
总结:
1.promise有且只有三个状态:pending、fulfilled、rejected,状态之间的转换是只允许pending转向fulfilled或rejected,其它任何状态都不能相互转换。
2.封装的nextTick函数是用来兼容node环境和浏览器环境的,如果是node环境会直接使用process.nextTick;如果是浏览器环境,使用MutationObserver API来实现。(MutationObserver 接口提供了监视对 DOM 树所做更改的能力)
3.注意在写调用函数时,多想想函数的this是什么,是否符合我们预期的this,如果不符合,就需要使用bind或call方法指定函数的this。
下面是一个MutationObserver例子
<html>
<p id="domp">111</p>
</html>
<script>
setTimeout(()=>{
console.log('setTimeout')
})
nextTick(()=>{
console.log('nextTick执行了')
})
domp.innerHTML = 'hello'
new Promise((resolve,reject)=>{
console.log('new promise')
resolve()
}).then(()=>{
console.log('promise.then执行了')
})
/*
new promise
nextTick执行了
promise.then执行了
setTimeout
*/
function nextTick(fn) {
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);
}
</script>