手写promise
这次的博客就是这么干,赋值粘贴就能运行。
前序
js底层的promise是用c写的, 这里只是用js写了个思路来实现。
promise脑图
使用守则和注意事项
- 建议把代码复制到本地编辑器查看。
- 创建一个html文档,在html文档里的script里面引入KPromise模块
- 注意要把script的type=‘module’,并且需要在本地起服务打开,否则不能引入KPromise模块
- 创建一个名为KPrimise.js的文件,把下面的js代码赋值粘贴。
html文件
<script type='module'>
import KPromise from './KPromise'
const p1 = new KPromise((resolve, reject)=>
resolve('ok')
// reject('err')
).then(res => {
console.log(res)
}, err => {
console.log(err)
})
</script>
KPromise.js
export default class KPromise {
constructor(handle) {
this.state = "pending";
this.result = undefined;
this.resolveQueue = [];
this.rejectQueue = [];
handle(this._resolve.bind(this), this._reject.bind(this));
}
_resolve(val) {
this.state = "fulfilled";
this.result = val;
// 异步执行then里面的语句,把run微任务异步执行
const run = () => {
let cb;
while ((cb = this.resolveQueue.shift())) {
cb && cb(val);
}
};
let ob = new MutationObserver(run)
ob.observe(document.body, {
attributes: true
})
document.body.setAttribute('joy', 'joy')
}
_reject(err) {
this.state = "rejected";
this.result = err;
// 异步执行then里面的语句
const run = () => {
let cb;
while ((cb = this.rejectQueue.shift())) {
cb && cb(err);
}
};
let ob = new MutationObserver(run)
ob.observe(document.body, {
attributes: true
})
document.body.setAttribute('joy', 'joy')
}
// then返回的是promise实例
// then 执行里面方法的时候可以改变其状态
then(onResolved, onRejected) {
return new KPromise((resolve, reject) => {
// 把onResolved 存入 resolveFn队列
let resolveFn = (val) => {
let res = onResolved && onResolved(val);
if (res instanceof KPromise) {
// 如果是KPromise就递归
res.then(resolve, reject);
} else {
resolve(res);
// resolve方法的功能:
// 1. 改变state为fulfilled
// 2. 生成一个异步方法run,传入val
}
};
let rejectFn = (err) => {
let res = onRejected && onRejected(err);
if (res instanceof KPromise) {
res.then(resolve, reject);
} else {
resolve(res);
// 如果返回的结果是undefined或者常量,state = fulfilled, result(res)
}
};
this.resolveQueue.push(resolveFn);
this.rejectQueue.push(rejectFn);
});
}
finally(callBack){
return this.then(callBack, callBack)
}
static resolve(val) {
// 获取一个promise实例。如果返回的结果是Promise
return new KPromise((res, rej) => {
if (val instanceof KPromise) {
val.then(res, rej);
} else {
res(val);
}
});
}
static reject(val) {
return new KPromise((res, rej) => {
if (val instanceof KPromise) {
val.then(res, rej);
} else {
res(val);
}
});
}
static all(lists) {
// 返回一个promise实例,因为后面需要then
return new KPromise((resolve) => {
let resArr = [];
let num = 0;
// 把resolve(val) 这个val push进resArr, num++ 如果num和lists.length相等,说明每个
// 都是resolve,就把这个结果传给下一个promise
lists.forEach((item) => {
item.then((res) => {
resArr.push(res);
num++;
if (num === lists.length) {
console.log(resArr); // [11,22,33] 每一个resolve(val) 的val值
// resolve(resArr);
return resArr
}
});
});
});
}
static allSettled(lists) {
let resArr = new Array(lists.length);
let num = 0;
return new KPromise((resolve, reject) => {
lists.forEach((item, key) => {
let obj = {};
item.then(
(res) => {
// resolve下来的res传给obj['value']
obj["status"] = "fulfilled";
obj["value"] = res;
resArr[key] = obj;
num++;
//抛出resArr,在下一个Promise的resolve的函数里获取这个resArr
if (num === lists.length) {
resolve(resArr);
}
},
(err) => {
obj["status"] = "rejected";
obj["reson"] = err;
resArr[key] = obj;
num++;
// 如果最后一个是rejected,也是传给下一个Promise的resolve的函数里,当then的时候,可以在resolve的函数里获取这个resArr
if (num === lists.length) {
resolve(resArr);
}
}
);
});
});
}
}
- 该Promise还有一些bug还没有解决,就是当throw err的时候,会抛错,并且不会执行接下来的方法,包括finally
let p1 = new KPromise((resolve, reject) => {
setTimeout(() => {
//resolve(111)
reject(222)
}, 1000)
})
p1.then(res => {
console.log(res)
console.log('world')
}, err => {
console.log(err)
throw err
}).then(res => {
console.log('hello')
}, err => {
console.log(err)
}).finally(() =>{
console.log('finally')
}
)