今天教你手写 Promise
Posted 小北哥哥和北妈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了今天教你手写 Promise相关的知识,希望对你有一定的参考价值。
大家好,我是梦起
今天我们来聊聊常见的前端手写功能之Promise
首先我们来聊聊要实现的功能:
1、Promise就是一个类,在执行类的时候,需要传递一个执行器(函数)进去,执行器会立刻执行
2、Promise有三种状态,分别为 等待 pending 成功 fulfilled 失败 rejected
pending => fulfilled || pending => rejected
状态一旦确定就不能改变
3、resolve和reject是用来更改状态的
resolve : fulfilled
reject : rejected
4、then方法内部做的事情就是判断状态 如果状态是成功 调用成功的返回函数 如果状态是失败 调用失败的回调函数 then方法是被定义在原型对象中的
5、then成功回调有一个参数,表示成功之后的值,then失败回调有一个参数,表示失败的原因
6、同一个promise对象下面的then方法是可以被调用多次的,then方法是可以链式调用的,后面的then方法回调函数拿到的值是上一个then方法的回调函数的返回值
确定功能后呢,接下来我们就要开始写代码了
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise
constructor (executor)
try // 尝试调用执行器
executor(this.resolve,this.reject)
catch(e) // 调用失败
this.reject(e)
// Promise 状态初始化为等待
status = PENDING;
// 成功之后的值
value = undefined;
// 失败的原因
reason = undefined;
// 成功的回调函数存放的数组
successCallback = [];
// 失败的回调函数存放额数组
failCallback = [];
resolve = value =>
// 如果状态不是等待 阻止程序向下执行
if(this.status !== PENDING) return
// 更改状态为成功
this.status = FULFILLED
// 保存成功之后的值
this.value = value
// 成功回调存在 调用成功回调方法
// this.successCallback && this.successCallback(this.value)
// 因为then是可以多次调用的
// this.successCallback.shift(),截取数组中的第一个元素并返回,会改变原数组
while(this.successCallback.length) this.successCallback.shift()(this.value)
reject = reason =>
if(this.status !== PENDING) return
// 更改状态为失败
this.status = REJECTED
// 保存失败的值
this.reason = reason
// 成功回调存在 调用成功回调方法
// this.failCallback && this.failCallback(this.value)
while(this.failCallback.length) this.failCallback.shift()(this.value)
then(successCallback, failCallback)
// 当没有成功回调时,将value值往下传递
successCallback = successCallback ? successCallback : value => value;
// 当没有失败回调时,抛出异常
failCallback = failCallback ? failCallback : reason => throw reason ;
// 创建一个新的 Promise对象
let promise2 = new MyPromise((resolve, reject)=>
// 判断状态
if(this.status === FULFILLED)
setTimeout(()=>
try
// 定义 val接收成功回调的返回值
let x = successCallback(this.value);
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
catch(e)
reject(e)
,0)
else if(this.status === REJECTED)
setTimeout(()=>
try
// 定义 val接收成功回调的返回值
let x = failCallback(this.reason)
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
catch(e)
reject(e)
,0)
else
// 当异步改变状态时,此时状态为 pending,将成功或失败回调缓存起来
// 每次调用 then方法 ,都会缓存一个回调
this.successCallback.push(() =>
setTimeout(()=>
try
// 定义 val接收成功回调的返回值
let x = successCallback(this.value);
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
catch(e)
reject(e)
,0)
)
this.failCallback.push(() =>
setTimeout(()=>
try
// 定义 val接收成功回调的返回值
let x = failCallback(this.reason)
// resolve(val)
// 判断val的值是一个普通值,还是promise对象,
// 如果是普通值,直接调用resolve
// 如果是promise对象,查看promise对象返回的结果
// 再根据promise对象返回的结果,决定调用resolve还是reject
resolvePromise(promise2, x, resolve, reject)
catch(e)
reject(e)
,0)
)
)
// 返回一个 Promise对象
return promise2;
catch(failCallback)
return this.then(undefined, failCallback)
finally(callback)
// 无论成功或失败都要执行
return this.then(value=>
return MyPromise.resolve(callback()).then(() => value)
,reason =>
return MyPromise.resolve(callback()).then(() => throw reason)
)
static all(array)
let result = []
let index = 0 // 由index判断是否执行完所有代码,并将数据添加进result中了
return new MyPromise((resolve, reject) =>
// 由addData方法像 result 中添加数据
function addData(key, val)
result[key] = val
index ++
if(index == array.length)
resolve(result)
array.forEach((item,index) =>
if(item instanceof MyPromise)
item.then(val => addData(index,val), reason => reject(reason))
else
addData(index,item)
)
)
static resolve(val)
// promise对象直接原样返回
if(val instanceof MyPromise) return val;
// 数值类型将其作为一个新的promise对象的返回值返回
return new MyPromise(resolve => resolve(val))
function resolvePromise(promise2, x, resolve, reject)
if(promise2 === x)
// console.log('传入了同一个promise');
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
if(x instanceof MyPromise)
// promise对象
// x.then(value => resolve(value), reason => reject(reason))
// 优化为:
x.then(resolve, reject)
else
// 普通值
resolve(x)
以上是关于今天教你手写 Promise的主要内容,如果未能解决你的问题,请参考以下文章