一、什么是Promise?
Promise是异步微任务,解决了传统回调函数的嵌套问题。简化了代码的书写,解决了异步多层嵌套回调的问题,让代码的可读性更高。Promise我们都会用,那它的原理是什么呢?
二、分析Promise
1. Promise是ES6新增的一个构造函数,可以用new Promise() 出一个实例对象。这个构造函数接收一个函数作为参数,这个函数有两个参数,分别是两个函数 resolve和reject。而这个实例对象又可以使用.then和.catch两个方法。返回出来的还是一个Promise对象,所以Promise可以链式调用。
所以我们可以写出大体的一个框架:
- 定义几个公共的状态变量
- 定义几个变量以便后面使用
- 构造函数内定义
resolve和reject两个函数 - 构造函数外部有
then和catch两个函数
//定义公共状态变量
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class MyPromise{
constructor(fn){
this.state = PENDING //起始状态
this.value = null //用来存放resolve() 内部的参数
this.resloveCallBacks = [] //存放.then() 里面的回调函数
this.rejectCallBacks = [] //存放 .catch() 里面的回调函数
let resolve = value =>{}
let reject = value =>{}
try {
fn(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFufilled,onRejected){}
catch(onFufilled,onRejected){}
}
2. 大体框架写好之后我们再次分析
- Promise的状态一经变更之后,是不可逆转的。所以我们要在
resolve和reject两个函数判断。只有为pending状态时才执行。 - Promise的
resolve或reject一经调用,马上会执行.then()里面的函数。 代码变更为:
let resolve = value =>{
if(this.state === PENDING){
this.state = RESOLVED
this.value = value
this.resloveCallBacks.map(cb =>cb(this.value)) //立即执行.then()里面的回调函数
}
}
let reject = value =>{
if(this.state === PENDING){
this.state = REJECTED
this.value = value
this.rejectCallBacks.map(cb => cb(this.value))
}
}
3. 然后再对then分析
- then 可以接收两个回调函数,一个成功,一个失败。
- then 里面的回调函数的值就是resolve或reject出来的值。
- then 里面的参数一定要是函数 所以代码变更为:
then(onFufilled,onRejected){
//先判断参数的类型
if(typeof onFufilled === 'function' ? onFufilled : v => v)
if(typeof onRejected === 'function' ? onRejected : r =>{
throw r
})
if(this.state == PENDING){ //如果还是pending状态,不执行后面的函数
this.ResolvedFunctions.push(onFufilled) //将函数存入相对应的数组
this.RejectedFunctions.push(onRejected)
}
if(this.state == RESOLVED){ //已经调用
onFufilled(this.value) //立即执行回调函数
}
if(this.state == REJECTED){
onRejected(this.value)
}
}
完整代码:
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class MyPromise{
constructor(fn){
this.state = PENDING //保存状态
this.value = null // 保存resolve() 和 reject() 的参数
this.ResolvedFunctions = [] //保存then 里面的第一个函数
this.RejectedFunctions = [] //保存then 里面的第二个函数
let resolve = value =>{
if(this.state === PENDING){
this.state = RESOLVED
this.value = value
this.ResolvedFunctions.map( cb => cb(this.value))
}
}
let reject = value =>{
if(this.state === PENDING){
this.state = REJECTED
this.value = value
this.RejectedFunctions.map( cb => cb(this.value))
}
}
try {
fn(resolve,reject)
} catch (error) {
reject(error)
}
}
then( onFufilled,onRejected){
//判断参数是否为函数类型
if(typeof onFufilled === 'function' ? onFufilled : v => v)
if(typeof onRejected === 'function' ? onRejected : r => {r
throw r
})
if(this.state == PENDING){
this.ResolvedFunctions.push(onFufilled)
this.RejectedFunctions.push(onRejected)
}
if(this.state == RESOLVED){
onFufilled(this.value)
}
if(this.state == REJECTED){
onRejected(this.value)
}
}
}
这样一个最丐版的Promise就写好了,我们来测试一下:
const p =new MyPromise((resolve,reject) =>{
setTimeout(() =>{
resolve('yes')
},1000)
})
p.then(
res =>{
console.log(res);
})
测试结果:我们可以看到在过了一秒,reslove执行完之后,才会执行.then()
4.链式调用
then会有几个特点:
- 1、then方法本身会返回一个新的Promise对象
- 2、如果返回值是promise对象,返回值为成功,新promise就是成功
- 3、如果返回值是promise对象,返回值为失败,新promise就是失败
- 4、如果返回值非promise对象,新promise对象就是成功,值为此返回值 那么如何链式调用呢,将then再次封装成一个Promise对象返回
具体代码如下:
then(onFufilled,onRejected){
if(typeof onFufilled === 'function' ? onFufilled : v => v)
if(typeof onRejected === 'function' ? onRejected : r =>{
throw r
})
//返回一个Promise对象
var thenPromise = new MyPromise((resolve,reject) =>{
const resolvePromise = cb =>{
try {
const x = cb(this.value)
if(x === thenPromise){
throw new Error('不能返回自身')
}
//如果还是Promise对象,则继续调用then方法
if(x instanceof MyPromise){
x.then(resolve,reject)
}else{
//否则直接成功
resolve(x)
}
} catch (error) {
reject(error)
throw new Error(error)
}
}
if(this.state === PENDING){
// 如果状态为待定状态,暂时保存两个回调
this.resloveCallBacks.push(resolvePromise.bind(this,onFufilled))
this.rejectCallBacks.push(resolvePromise.bind(this,onRejected))
}
if(this.state === RESOLVED){
// 如果当前为成功状态,执行第一个回调
resolvePromise(onFufilled)
}
if(this.state === REJECTED){
// 如果当前为失败状态,执行第二个回调
resolvePromise(onRejected)
}
})
return thenPromise
}
我们测试用例:
const p = new MyPromise((resolve,reject) =>{
resolve(2)
}).then(res =>2 * res)
.then(res =>{
console.log(res);
})
用例结果:输出了第二个then的执行结果
这就是Promise的手写过程,希望能对你理解Promise有一定的帮助。