把Promise手写明白!
就是说,把这个最爱考的手写系列给它整明白!总结加理解加多复习,我就不信还能有什么别的花样!
先介绍一下promsie的特点,三个状态pending、reject、fullfilled(resolved),状态只能从pending到另外两个,一经生成不可再改变,然后具有.then、.finally、.all、.race等函数进行使用
-
抽象表达:
Promise 是一门新的技术(ES6 规范)
Promise 是 JS 中进行异步编程的新解决方案
备注:旧方案是单纯使用回调函数 -
具体表达:
从语法上来说: Promise 是一个构造函数
从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/
失败的结果值 -
为何要用promsie?
1、指定回调函数的方式更加灵活
2、支持链式调用,解决回调地狱的问题
//一个普通的promise的使用
const p = new Promise((resolve,reject) => {
setTimeout(() => {
let n = Math.random()*100;
if(n < 30){
resolve(n);
}else{
reject('errrro发生错误');//返回的是一个prmise对象,且状态设置为失败,值为n
}
},1000)
})
console.log(p)
p.then((value) => {
console.log('成果'+value)
},(err) => {
console.log('shibai'+err)
})
所以手写的就要实现基本的功能,一个构造promise,resolve、reject回调函数,返回promise还要支持then的调用
手写Promsie函数
const promiseA = new Promise( (resolve,reject) => {
resolve(777);
});
- 传入了一个函数,而且这个函数被立即执行,不仅如此,这个函数还会立即执行resolve和reject。说明构造函数里有resolve和reject方法。因此我们可以初步实现:
- 每个promise都有一个状态可能为pending或resolved,rejected。而且初始状态都为pending。因此需要添加个status来表示当前promise的状态.。并且每个promise有自己的data。
- 不管是Promise原型对象上的方法还是Promise函数对象上的方法 ,它们的执行结果都将返回一个Promise对象
// 例1
var promise = new Promise((resovle,reject)=>{
})
promise.then(resolve=>{
},reject=>{
})
这种情况,当状态为pending的时候,要把then里面的回调函数保存起来,所以需要一个callbacks数组,等prmsie里面的resolve或足额reject之后再执行;
那么then函数是如何把传入的回调收集起来的,就是叛党当前promsie的状态是否为pending
举一个例子
// 例2
var promise = new Promise((resolve,reject)=>{
setTimeout(function () {
resolve(1)
})
})
promise.then(
value=>{
console.log(value)},
err=>{
console.log(err)}
)
- 先执行new Promise里的代码,然后发现个定时器,js线程将定时器交给定时器线程处理,2. 然后继续执行下面的代码,发现是then,而且当前的promise还是pending的状态。就把then里的回调函数放到callbacks中。
- 5秒后定时器线程将定时器里的回调函数(也就是宏任务)放到消息队列中,js线程在消息队列里发现了这个宏任务,就把它拿来执行。- - 执行这个宏任务,就执行了resolve(1),此时promise的callbacks里的回调被执行。并将当前promise状态改为resolved。然后这个1也会被 保存到当前promise对象中
那怎么实现resolve呢?依旧上面的描述,就知道resovle的功能是执行callbacks里的函数,并保存data,并将当前promise状态改为resolved。所以我们可以这么实现
执行到then时,promise可能会是pending状态,此时就要把then里的回调函数保存起来,也可能会是resolved或者rejected状态,此时就不用把回调保存起来,直接执行onResolved或onRejected方法。注意是异步执行。而且是做为微任务的,这里我们简单的用setTimeout来实现就好了。
function Promsie(callback) {
this.state = PENDING;
this.value = null;
this.resolvedCallbacks = []
this.rejectedCallbacks = []
callback(value => {
if(this.state == PENDING){
this.state = RESOLVED
this.value = value
this.resolvedCallbacks