共计 2804 个字符,预计需要花费 8 分钟才能阅读完成。
promise 的用法简单介绍一下,我觉得如果有人愿意看这篇文章,对 promise 的用法多多少少也了解;
new Promise((res, rej) => {
try{
执行函数;
res(data)
} catch(e){rej(e);
}}).then(resCb, rejCb).then(cb);
心血来潮,今天去自己试着写了一下 promise。先说下我个人对 promise 的理解
1.promise 从表现形式上看,是将执行函数的返回值通过 resolve 或者 reject 抛出 data,再在 then 函数里面处理 data
2.promise 可以链式调用 then, 上一个 then 的返回值作为下一个 then 中函数的实参
但实际上,promise 并非一定是在 then 里面执行的,尤其是异步的时候,理应在实例函数中执行,才符合我们对单线程的理解。
promise 简单点说分为两部分。一个是实例化 时候,传入的执行函数 , 另一部分为 then 中传入的回调函数 这个关系就好比 监考老师 和 学生
如果监考老师 先到了教室,那么自然而然,学生是直接依次进入教室;(实例函数执行较快,超过了 then 的声明)
如果监考老师 在学生们后面到,那么学生们只能按顺序排队在门口等监考老师;(实例函数执行较慢)
也就是说,执行函数和 then 函数的声明,先后顺序并非固定(一般情况下 then 声明先完成)
这个时候就需要一个状态码去判断到底是哪种情况(’default’, ‘resolve’ ,’reject’)
为了方便理解,可以把 resolve 和 reject 看成同一类型
我先直接发代码写注释
时间有限,本次先不考虑 then 中函数 存在异步的问题
// 简述下逻辑:
//1. 定义一个 state 是用来判断 then 和 实例化时候传入的函数 哪一个先完成
// 也就是刚刚说的监考老师和学生的问题。默认值为 default, 默认老师没到(实例函数未执行完成)//2. 定义 resolve_ 用来存放 then 中定义的方法,相当于学生排队的过道,便于按顺序执行,reject_同理, 以下不再重复
//3. 定义 resolveData 用来记录抛出值,也就是 res(data) 中的 data,作为 then 中方法的参数
//4. 在 res 抛出值的时候,将 state 改成 resolve,相当于表明监考老师到教室了
// 如果 resolve_队列中已经有定义函数就依次执行它们,相当于如果有学生就进教室。//5.then 方法声明时候,检测状态 state 是不是 default,如果是,说明还没有抛出值,// 相当于监考老师还没到,学生都去排队,加入到 resolve_队列;// 如果状态已经不是 default,那么说明监考老师已经到了,学生不用排队,直接进教室; 也就是方法直接执行
new promise_((res, rej) => res(3)).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6
针对实际例子说一下
上面的例子明显就是 res(3) 先执行完成,然后执行 then 的函数
相当于监考老师先到了教室,那么,then 中的定义的函数就应该直接执行
new promise_((res, rej) => setTimeout(() => res(3), 1000).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6
上面的例子明显就是 then 先定义完成,然后 res 才抛出值
相当于监考老师后到了教室,那么,then 中的定义的函数就应该默默排队等待
因为 then 和 实例函数 两者顺序并不确定,所以 then 时候要通过 state 判断实例函数 是否执行完成,
同时,实例函数执行完成抛出值时,也需要检测一下 resolve_队列,判断 then 是否已经声明完成。
class promise_ {constructor(func) {if(typeof func !== 'function'){throw Error('实例化中传参必须为函数');
return;
} // 判断下是否传入的是函数,与逻辑无关,直接往下看
this.state = 'default'; // 用来判断
this.resolve_ = []; // then 中 reslove 的方法队列,用来接收 resolve 方法
this.reject_ = []; // then 中的 reject 的方法队列,用来接收 reject 方法
this.resolveData = null; // resolve 的抛出值
this.rejectData = null; // reject 的抛出值
func(this.resolve.bind(this), this.reject.bind(this)); // 实例化时候传入的函数
}
then(cb, errCb) {if(typeof cb !== 'function' || (errCb && typeof cb !== 'function')) {throw Error('then 参数,成功回调函数,失败回调函数');
return;
} // 日常判断是不是传参正确,和逻辑无关
switch(this.state) { // 检测一下监考老师来没来教室
case 'default': this.resolve_.push(cb); this.reject_.push(errCb); break;// 如果监考老师没到场,排队
case 'resolve': this.resolveData = cb(this.resolveData); break; // 如果监考老师到场,直接进来,因为链式调用,所以执行后把抛出值改一下,方便后面的 then 用
case 'reject': this.rejectData = errCb(this.rejectData); break;// 如果监考老师到场,直接进来,因为链式调用,所以执行后把抛出值改一下,方便后面的 then 用
default: break;
}
return this; // 链式调用
}
resolve(data) {if(!data) return; // 判断有无参数,和逻辑无关
this.resolveData = data; // 设定抛出值
this.state = 'resolve'; // 将状态设置为 resolve,表示监考老师到场了
while(this.resolve_.length) // 先进先出,依次执行 then 中函数
this.resolvedata = this.resolve_.shift()(data);
}
reject(data) {if(!data) return;
this.rejectData = data;
this.state = 'reject';
while(this.reject_.length)
this.rejectData = this.reject_.shift()(data);
}
}