想要知道如何手写Promise,首先我们需要清楚Promise有哪些优点,以及它解决了什么问题,Promise都有哪些方法和属性,这些方法和属性是如何实现的,我们都知道promise主要是为了解决异步调用,地域回调的问题,我们都知道,promise有3个状态,分别是pengding(创建promise的默认状态),fullfilled(成功后的状态),rejected(失败的状态),以及promise有.then()方法,并且可以链式调用,有.resolve()以及.reject()方法.一下是用代码展示:
const p= new Promise(()=>{})
p.then(()=>{},()=>{})
const p1=Promise.resolve()
const p2=Promise.reject()
如果我们要手写一个Promise,从上面的代码中,我们可以梳理出一个思路: 1.new Promise,证明Promise是一个类,我们在new Promise的时候,必须要传一个处理函数,构造函数有一个函数形参,并且需要立即调用执行 2.promise的默认状态是pending,所以有个state属性,默认值是penging 3.promise类里面有resolve,.reject,以及then方法, 这个时候我们就可以构建出一个大致的结构;
class MyPromise{
state:"pending",//promise状态变量,默认pending
construct(fn:function){
if(typeof fn!=='function'){
throw new Error('new Promise()初始化必须传入一个函数');//如果传入的不是一个函数给出提示
}
fn()//立即调用
}
resolve(){}
reject(){}
then(){}
}
这样promise类的大致结构就形成了,接下来我们来分析一下,每个方法都有哪些特征,以及每个方法都做了什么事情, 我们先来看看then方法吧,我们先看代码p.then(()=>{},()=>{}), 1.我们可以看到then方法中有2个函数形参,当然可传也可以不传,当执行成功的时候,执行的是resolve方法,失败的时候是reject方法 2.又因为then是可以链式调用的,最后返回的也是一个promise,所以我们接着填充上面的代码:
class MyPromise{
callbacks:any[]//其实是一个二维数据
state:"pending",//promise状态变量,默认pending
construct(fn:function){
if(typeof fn!=='function'){
throw new Error('new Promise()初始化必须传入一个函数');//如果传入的不是一个函数给出提示
}
fn(this.resolve.bind(this), this.reject.bind(this))//立即调用并改变this指向
}
resolve(result){
setTimeout(()=>{
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.callbacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
handle[0].call(undefined, result);//result 默认传递的第一个参数
}
});
},0)
}
reject(reason){
setTimeout(() => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.callbacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
handle[1].call(undefined, reason)
}
});
}, 0);
}
then(succeed?, fail?){
const handle: any[] = [];
if (typeof succeed === 'function') {
handle[0] = succeed;
}
if (typeof fail === 'function') {
handle[1] = fail;
}
handle[2] = new Promise1(() => {});
this.callbacks.push(handle);
return handle[2];//返回一个promise
}
}
这样一个简单的promise就完成了,如果想要更加的话,可以增加以下代码:
class MyPromise{
callbacks:any[]//其实是一个二维数据
state:"pending",//promise状态变量,默认pending
construct(fn:function){
if(typeof fn!=='function'){
throw new Error('new Promise()初始化必须传入一个函数');//如果传入的不是一个函数给出提示
}
fn(this.resolve.bind(this), this.reject.bind(this))//立即调用并改变this指向
}
resolve(result) {
setTimeout(() => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.callbacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
const x = handle[0].call(undefined, result);
handle[2].resolveWith(x, result);
}
});
}, 0);
}
reject(reason) {
setTimeout(() => {
if (this.state !== 'pending') return;
this.state = 'reject';
this.callbacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
const x = handle[1].call(undefined, reason);
handle[2].resolveWith(x, reason);
}
});
}, 0);
}
then(succeed?, fail?) {
const handle: any[] = [];
if (typeof succeed === 'function') {
handle[0] = succeed;
}
if (typeof fail === 'function') {
handle[1] = fail;
}
handle[2] = new Promise1(() => {});
this.callbacks.push(handle);
return handle[2];
}
resolveWith(x) {
if (this === x) {
return this.reject(new TypeError('cannot resolve'));
}
if (x instanceof Promise1) {
x.then(
(result) => {
this.resolve(result);
},
(reason) => {
this.reject(reason);
}
);
}
if (x instanceof Object) {
let then;
try {
then = x.then;
} catch (err) {
this.reject(err);
}
if (typeof then === 'function') {
try {
then.call(
x,
(y) => {
this.resolveWith(y);
},
(r) => {
this.reject(r);
}
);
} catch (e) {
this.reject(e);
}
} else {
this.resolve(x);
}
} else {
this.resolve(x);
}
}
}
OK,到这里我们就手写了一个比较OK的Promise啦!当然这个代码是可以优化和精简的,我只是为了能够让大家看到promise的每个构建步骤,就没有进行代码优化,有兴趣的小伙伴可以继续完善呀!