Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【前端成长之路】手写Promise,深入理解Promise的使用和实现 #23

Open
AmamiyaCx opened this issue Sep 18, 2022 · 0 comments

Comments

@AmamiyaCx
Copy link
Owner

AmamiyaCx commented Sep 18, 2022

Promise是ES6新增为了解决异步编程的一种实现方案,配合asyncawiat可以做到更加优雅的书写异步任务并且实现同步执行。Promise意为承诺,承诺会在未来某个时间返回操作的结果

Promise几个简单示例:

let p = new Promise((resolve, reject) => {
    console.log(1);
    setTimeout(() => {
        resolve('then');
    }, 3000);
});

let p1 = new Promise(); // TypeError: Promise resolver undefined is not a function

p.then(res => console.log(1)); // '1', 3s -> 'then'

这个实例可以得到Promise的以下特点

  • new Promise后会立即执行,并且接收一个必传函数作为参数

  • 接收的函数中有2个参数

  • 值需要使用then方法获取

let p2 = new Promise((resolve, reject) => {
    resolve('成功');
    reject('失败');
})
console.log('p2', p2); // { PromiseState: 'fulfilled', PromiseResult: '成功' }

let p3 = new Promise((resolve, reject) => {
    reject('失败')
    resolve('成功')
})
console.log('p3', p3); // { PromiseState: 'rejected', PromiseResult: '失败' }

let p4 = new Promise((resolve, reject) => {
    throw('报错'); // { PromiseState: 'rejected', PromiseResult: '失败' }
})
console.log('p4', p4);

这个实例可以得到Promise的以下特点

  • 有三种状态:初始pending,成功fullfilled,拒绝rejected,并且状态只能从pending转变为fulfilled或者rejected,不可逆
  • resolve将状态转变为fulfilledreject将状态转变为rejected
  • 一旦状态从pending转变为fulfilled或者rejected就不会再改变了

1、根据前面的总结定义好初始结构

// 定义promise的状态
const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    // 接收一个函数作为参数
    constructor(executor) {
        // 初始状态为pending
        this.status = PENDING;
        // new Promise后立即执行,接收2个参数
        executor(resolve, reject);
    }
    // 获取结果的函数
    then() {}
}

根据第二个示例我们可以看到p3中抛出错误也是被rejected的,所以优化下结构:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    constructor(executor) {
        this.status = PENDING;
        // 新增try-catch捕获错误,出错时将状态转变为rejected
+       try {
         	executor(resolve, reject);   
+       } catch (error) {
            reject(error);
+       }
    }
    then() {}
}

2、实现resolve、reject方法

在前面的示例中已经知道promise传入的函数接收2个参数,也就是resolvereject,他们的作用就是改变promise的状态。

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    constructor(executor) {
        this.status = PENDING;
        try {
+           executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
         	this.reject(error);
        }
    }
+   resolve() {}
+   reject() {}
    then() {}
}

状态只能从pending转变为fullfilledrejected,并且不可逆:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    constructor(executor) {
        this.status = PENDING;
        try {
            executor(this.resolve, this.reject);
        } catch (error) {
         	this.reject(error);
        }
    }
	resolve() {
        // 状态为pending才改变状态
+       if (this.status === PENDING) {
+          this.status = FULLFILLED;
+       }
  	}
  	reject() {
        // 状态为pending才改变状态
+    	if (this.status === PENDING) {
+      		this.status = REJECTED;
+    	}
  	}
  	then() {}
}

根据示例可以看到调用resolvereject时可以传递参数,最后可以通过调用then获取结果。

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    constructor(executor) {
        this.status = PENDING;
        // 保存结果,最终返回
+       this.value = null;
        try {
            executor(this.resolve, this.reject);
        } catch (error) {
         	this.reject(error);
        }
    }
+	resolve(value) {
        // 状态为pending才改变状态
        if (this.status === PENDING) {
          	this.status = FULLFILLED;
+           this.value = value;
        }
  	}
+  	reject(reason) {
        // 状态为pending才改变状态
    	if (this.status === PENDING) {
      		this.status = REJECTED;
+           this.value = reason;
    	}
  	}
  	then() {}
}

3、实现then方法

then方法返回一个Promise。它最多需要两个参数:Promise的成功和失败情况的回调函数(失败情况的回调函数为可选)——MDN

// 接收两个参数
then(onFullfilled, onRejected) {
    // 返回一个Promise
    return new _Promise((resolve, reject) => {});
}

因为then方法返回了promise,而promise上又有then方法,所以可以链式调用,例如:

let p = new Promise((resolve, reject) => {
    resolve(1);
});
p.then(res => {
    console.log(res);
    return res += 1;
}).then(res => {
    console.log(res);
    return res *= res;
}).then(res => {
    console.log(res);
}); // 1,2,4

先看下原生方法的执行结果:

let p = new Promise((resolve, reject) => {
    resolve('成功');
    reject('失败');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 成功

// 反过来
let p = new Promise((resolve, reject) => {
    reject('失败');
    resolve('成功');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 失败

new Promise时接收2个参数,分别为将状态转变为fullfilledrejected的回调函数。而then方法也是接收2个参数,分别为promise的成功和失败情况的回调函数。所以根据结果可以知道then方法就是在根据promise的状态执行对应的方法

// 接收两个参数
then(onFullfilled, onRejected) {
    // 如果状态为fullfilled,调用成功回调并将resolve时带来的参数传入并执行
+   if (this.status === FULLFILLED) {
+       onFullfilled(this.value);
+   }
    // 如果状态为rejected,调用失败回调并将reject时带来的参数传入并执行
+   if (this.status === REJECTED) {
+       onRejected(this.value);
+   }
    // 返回一个Promise
    return new _Promise((resolve, reject) => {});
}

暂时基本功能都有了,进行一下测试:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    constructor(executor) {
       	this.status = PENDING;
       	this.value = null;
        try {
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
         	this.reject(error);
        }
    }
	resolve(value) {
        if (this.status === PENDING) {
          	this.status = FULLFILLED;
           	this.value = value;
        }
  	}

  	reject(reason) {
    	if (this.status === PENDING) {
      		this.status = REJECTED;
           	this.value = reason;
    	}
  	}

    then(onFullfilled, onRejected) {
      	if (this.status === FULLFILLED) {
           onFullfilled(this.value);
      	}

       	if (this.status === REJECTED) {
           onRejected(this.value);
       	}

        return new _Promise((resolve, reject) => {});
    }
}

// 测试代码
let p = new _Promise((resolve, reject) => {
    resolve('成功');
    reject('失败');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 成功
// 反过来
let p = new _Promise((resolve, reject) => {
    reject('失败');
    resolve('成功');
});
p.then(
    res => console.log(res),
    error => console.log(error)
); // 失败

和原生执行一样,成功!但是,忽略了一些细节,比如:

// 原生
let p = new Promise((resolve, reject) => {
    resolve('成功');
})
p.then(
    null, // 或undefined
    error => console.log(error)
); // 无输出无报错

// 自己实现的
let p = new _Promise(resolve => {
    resolve('成功');
});
p.then(
    null,
    error => console.log(error)
); // onFullfilled is not a function

因为我们在then方法中实现是直接执行传入的函数,当这个参数不是函数因为没有做处理,把不是函数的参数当做函数执行自然就会报错,所以在then函数中给参数加个处理

then(onFullfilled, onRejected) {
    // 判断如果传入的参数类型不为function,就给它赋值为一个函数
+   onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
+   onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }

    if (this.status === FULLFILLED) {
       onFullfilled(this.value);
    }

    if (this.status === REJECTED) {
       onRejected(this.value);
    }

    return new _Promise((resolve, reject) => {});
}

修改后再次执行之前的代码,发现就没有报错了

4、实现异步

到目前为止,代码里可以看到没有任何的特殊的东西,也就是说代码会正常按顺序同步执行。但是实际上不可能是都按照顺序同步执行的。众所周知JavaScript有个事件循环机制,将事件分为了同步任务异步任务两大类,接下来就要对异步任务进行处理,为什么呢?举个例子:

// 原生
console.log(1);
let p = new Promise((resolve, reject) => {
    console.log(2);
    resolve(4);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4

// 应用到自己实现的上
console.log(1);
let p = new _Promise((resolve, reject) => {
    console.log(2);
    resolve(4);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,4,3

在MDN有说明,promise的操作会被视为异步执行,所有的promise都是异步的,并且和setTimeout(action, 10)特别相似。那么我们就用``setTimeout`来模拟异步。

then(onFullfilled, onRejected) {
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }

    if (this.status === FULLFILLED) {
+       setTimeout(() => {
           	onFullfilled(this.value); 
+       });
    }

    if (this.status === REJECTED) {
+       setTimeout(() => {
			onRejected(this.value);
+       });
    }

    return new _Promise((resolve, reject) => {});
}

重新执行一下之前的代码,发现输出顺序就已经正确输出1,2,3,4了

5、处理收集回调

根据上一步骤可以知道promise和它的操作都是异步的。那么有怎么一种情况,我在promise里也写异步事件会怎么样呢。如果了解了事件循环的话应该会知道,这里暂且提一嘴

// 原生
console.log(1);
let p = new Promise((resolve, reject) => {
    console.log(2);
    setTimeout(() => {
        console.log(4);
        resolve(5);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);

事件循环解释一下上面代码执行的过程:

  1. 执行同步任务console.log(1);,输出"1"
  2. new Promise()立即执行,执行同步任务console.log(2);并输出"2",遇见异步任务setTimeout加入到宏任务队列(异步任务分为宏任务和微任务,promise的回调为微任务)
  3. 遇到p.then(),将其回调加入到微任务队列
  4. 执行同步任务console.log(3);并输出"3"
  5. 主线程执行栈清空,去寻找异步任务执行,发现同时存在宏任务和微任务,先执行微任务
  6. 执行微任务then回调,此时promise状态为pending不执行
  7. 执行同步任务console.log(4);并输出"4"
  8. 微任务执行完毕执行宏任务,执行同步任务console.log(4);并输出"4"
  9. 调用resolve(5);,此时promise状态改变,执行对应的回调,输出"5"

所以输出为:1,2,3,4,5

去_promise`上去,查看执行结果:

console.log(1);
let p = new _Promise((resolve, reject) => {
    console.log(2);
    setTimeout(() => {
        console.log(4);
        resolve(5);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4

发现执行结果少输出一个5,而5是执行then的回调打印的,那么可以猜测是then没有被执行。而我们的then中执行是进行了状态判断的,也就是说只有当promise状态为FULLFILLED或者REJECTED时才会执行。打印一下执行时的status看看是不是它的问题

console.log(1);
let p = new _Promise((resolve, reject) => {
    console.log(2);
    setTimeout(() => {
        console.log(4);
        console.log(p.status);
        resolve(5);
        console.log(p.status);
    }, 1000);
});
p.then(res => console.log(res));
console.log(3);
// 输出1,2,3,4,pending,fullfilled

继续用事件循环来梳理下执行过程:

  1. 执行同步任务console.log(1),输出"1"
  2. new Promise()立即执行,执行同步任务console.log(2);,输出"2"
  3. 遇到异步任务setTimeout加入到宏任务队列
  4. 遇到异步任务then回调,加入到微任务队列
  5. 执行同步任务console.log(3);,并输出"3"
  6. 主线程执行栈清空,去寻找异步任务执行,发现同时存在宏任务和微任务,先执行微任务
  7. 执行微任务then回调,此时promise状态为pending没有执行结果
  8. 微任务执行完毕执行宏任务,执行同步任务console.log(4);并输出"4"
  9. 执行console.log(p.status);,输出"pending"
  10. 执行resolve(5);promise状态改变为fullfilled
  11. 执行console.log(p.status);,输出"fullfilled"

观察执行过程可以发现,当promise的状态为pending时,自己实现的then方法中是没有做对应处理的。可能这就是导致了没有执行的问题。那么当状态为pending时我们应该做什么呢?

then(onFullfilled, onRejected) {
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }
+   if (this.status === PENDING) {
        // TODO: 状态为pending时应该做什么
+   }

    if (this.status === FULLFILLED) {
       	setTimeout(() => {
           	onFullfilled(this.value); 
       	});
    }

    if (this.status === REJECTED) {
       	setTimeout(() => {
			onRejected(this.value);
       	});
    }

    return new _Promise((resolve, reject) => {});
}

这里继续以执行顺序来理解。then函数是同步执行的,而获得结果是需要调用resolve或者reject的。那么我们怎么样才能保证then方法在获取到结果后才执行呢?解决办法就是收集回调`。

promise的状态为pending时,我们先将回调收集起来,等到执行resolve或者reject时,将对应的回调取出来一并执行。

1、创建数组收集回调,毕竟回调可能有多个
class _Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = null;
        // 收集成功的回调
+       this.fullfilledCallbacks = [];
        // 收集失败的回调
+       this.rejectedCallbacks = [];

        try {
          	executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
          	this.reject(error);
        }
	}
}
2、在then方法中收集回调
then(onFullfilled, onRejected) {
   	onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
   	onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }
    // 状态为pending时收集依赖
   	if (this.status === PENDING) {
+       this.fullfilledCallbacks.push(onFullfilled);
+       this.rejectedCallbacks.push(onRejected);
   	}

    if (this.status === FULLFILLED) {
       	setTimeout(() => {
           	onFullfilled(this.value); 
       	});
    }

    if (this.status === REJECTED) {
       	setTimeout(() => {
			onRejected(this.value);
       	});
    }

    return new _Promise((resolve, reject) => {});
}
3、resolve和reject方法中执行回调

在执行resolve()或者reject()时,会遍历保存的对应的回调数组(在执行then时保存的),并将参数传入执行。

resolve(value) {
    if (this.status === PENDING) {
        this.status = FULLFILLED;
        this.value = value;
        // 执行收集的回调
+       this.fullfilledCallbacks.forEach(callback => callback(value));
    }
}

reject(reason) {
    if (this.status === PENDING) {
        this.status = REJECTED;
        this.value = reason;
        // 执行收集的回调
+       this.rejectedCallbacks.forEach(callback => callback(reason));
    }
}

整体代码如下:

const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

class _Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = null;
        this.fullfilledCallbacks = [];
        this.rejectedCallbacks = [];

        try {
          	executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
          	this.reject(error);
        }
	}
    resolve(value) {
        if (this.status === PENDING) {
            this.status = FULLFILLED;
            this.value = value;
            this.fullfilledCallbacks.forEach(callback => callback(value));
        }
    }

    reject(reason) {
        if (this.status === PENDING) {
            this.status = REJECTED;
            this.value = reason;
            this.rejectedCallbacks.forEach(callback => callback(reason));
        }
    }
    then(onFullfilled, onRejected) {
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }
        if (this.status === PENDING) {
            this.fullfilledCallbacks.push(onFullfilled);
            this.rejectedCallbacks.push(onRejected);
        }

        if (this.status === FULLFILLED) {
            setTimeout(() => {
                onFullfilled(this.value); 
            });
        }

        if (this.status === REJECTED) {
            setTimeout(() => {
                onRejected(this.value);
            });
        }

        return new _Promise((resolve, reject) => {});
    }
}

再次执行之前测试的代码,发现then函数的回调触发了。但是细心点还是可以发现,在打印promise状态之后同步执行了resolve并触发了回调,这明显是不对的,我们期望的是resolvereject是异步执行的。所以这里使用setTimeout来模拟异步

resolve(value) {
    if (this.status === PENDING) {
+       setTimeout(() => {
           	this.status = FULLFILLED;
        	this.value = value;
        	this.fullfilledCallbacks.forEach(callback => callback(value)); 
+       });
    }
}

reject(reason) {
    if (this.status === PENDING) {
+       setTimeout(() => {
            this.status = REJECTED;
        	this.value = reason;
        	this.rejectedCallbacks.forEach(callback => callback(reason));
+       });
    }
}

再次测试输出结果,就会发现输出和原生一致了

4、测试多次执行then方法

原生promise可以多次调用then,同样的也给自己实现的进行一下测试

// 原生
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 2000);
})
p.then(value => {
    console.log(1)
    console.log('resolve', value)
})
p.then(value => {
    console.log(2)
    console.log('resolve', value)
})
p.then(value => {
    console.log(3)
    console.log('resolve', value)
})
// 1 resolve success 2 resolve success 3 resolve success

// 自己实现的
const p = new _Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 2000);
})
p.then(value => {
    console.log(1)
    console.log('resolve', value)
})
p.then(value => {
    console.log(2)
    console.log('resolve', value)
})
p.then(value => {
    console.log(3)
    console.log('resolve', value)
})
// 1 resolve success 2 resolve success 3 resolve success

没有问题,基本大功告成!剩下最后的promise链式调用

6、实现链式调用

首先用一个简单示例解释一下什么是链式调用

class Person {
    constructor() {
        this.name = '';
    }
    setName(name) {
        this.name = name;
        return this;
    }
    sayHello() {
        console.log(`hello,我叫${this.name}`);
        return this;
    }
}
// 使用
let p = new Person();
p.setName('哈哈哈').sayHello(); // hello,我叫哈哈哈

链式调用的核心就是上面的return this。当我们调用p.setName()时会返回自身实例,而实例上存在setNamesayHello两个方法,所以就能一直.setName()或者.sayHello()调用下去。

回到我们的then方法会发现在之前已经提前返回了一个new _Promise()。因为Promise要求then返回一个promise。所以这就是then方法能够链式调用的原因。还不明白可以认真立即上面这段话。

扩展:在以前使用Ajax发送请求时也会存在then回调,并且会出现因为then的无限嵌套回调而出现的回调地狱,解决办法就是使用基于Promise的asyncawait语法糖

在原生Promise中我们是这样使用链式调用的:

let p = new Promise((resolve, reject) => {
    resolve(1);
});
p.then(res => {
    console.log(res);
    return res + 1;
}).then(res => {
    console.log(res);
});
// 1,2

将同样的代码运用到自己实现的_Promise上后会发现有问题,因为我们then方法还没有完善,返回的_Promise里什么都没有。那么接下来就完善这个then方法。

1、首先将内容移动到返回的Promise中去
then(onFullfilled, onRejected) {
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }
        return new _Promise((resolve, reject) => {
            if (this.status === PENDING) {
                this.fullfilledCallbacks.push(onFullfilled);
                this.rejectedCallbacks.push(onRejected);
            }

            if (this.status === FULLFILLED) {
                setTimeout(() => {
                    onFullfilled(this.value); 
                });
            }

            if (this.status === REJECTED) {
                setTimeout(() => {
                    onRejected(this.value);
                });
            }
        });
    }
}
2、封装处理Promise返回内容的函数
function resolvePromise(promise2, x, resolve, reject) {
    // 不能返回自身
    if (x === promise2) {
        throw Error('不能返回自身');
    }
    // 如果是Promise
    if (x instanceof _Promise) {
        // 状态为pending
        if (x.status === PENDING) {
            // 收集回调等待执行
            x.then(
                y => resolvePromise(promise2, y, resolve, reject),
                reject
            )
        // 状态为fullfilled,调用resolve执行
        } else if (x.status === FULLFILLED) {
            resolve(x.value);
        // 状态为rejected,调用reject执行
        } else {
            reject(x.value);
        }
    // 如果是thenable对象(具有then属性)
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        let then = null;
        try {
            // 有then属性,赋值
            then = x.then;
        } catch (error) {
            // 获取不到then报错就调用reject
            reject(error);
        }
        // 如果then是个函数,就以promise相同方式调用
        if (typeof then === 'function') {
			let called = false; // 避免多次调用
            try {
                then.call(
                    x,
                    res => {
                        if (called) {
                            return;
                        }
                        called = true;
                        resolvePromise(promise2, res, resolve, reject);
                    },
                    error => {
                        // 防止多次调用
                         if (called) {
                            return;
                        }
                        called = true;
                        // 出错就调用reject
                        reject(error);
                    }
                )
            } catch (error) {
                // 防止多次调用
                if (called) {
                    return;
                }
                called = true;
                // 出错就调用reject
                reject(error);
            }
        } else {
            // 否则就是个正常值,执行调用resolve
            resolve(x);
        }
    // 否则直接调用resolve
    } else {
        resolve(x);
    }
}
3、修改then方法中的逻辑
then(onFullfilled, onRejected) {
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }
        let promise2 = new _Promise((resolve, reject) => {
            if (this.status === PENDING) {
                this.fullfilledCallbacks.push(() => {
                    try {
                        // 获取第一次promise执行后的值
                        let x = onFullfilled(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
                this.rejectedCallbacks.push(() => {
                    try {
                        // 获取第一次promise执行后的值
                        let x = onRejected(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }

            if (this.status === FULLFILLED) {
                setTimeout(() => {
                    try {
                        // 获取第一次promise执行后的值
                        let x = onFullfilled(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }

            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        // 获取第一次promise执行后的值
                        let x = onRejected(this.value);
                        // 使用封装的方法处理返回内容
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        // 遇到错误就调用reject
                        reject(error);
                    }
                });
            }
	});
    return promise2;
}

接下来进行测试:(随便找的一个例子)

// 原生
const p1 = new Promise((resolve, reject) => {
    resolve(1);          // 同步executor测试
})

p1.then(res => {
    console.log(res);
    return 2;          // 链式调用测试
}).then()             // 值穿透测试
.then(res => {
    console.log(res);
    return new Promise((resolve, reject) => {
        resolve(3);      // 返回Promise测试
    })
})
.then(res => {
    console.log(res);
    throw new Error('reject测试')   // reject测试
})
.then(() => { }, err => {
    console.log(err);
})
// 输出:1,2,3,Error: reject测试

// 自己实现的_Promise
const p1 = new _Promise((resolve, reject) => {
    resolve(1);          // 同步executor测试
})

p1.then(res => {
    console.log(res);
    return 2;          // 链式调用测试
}).then()             // 值穿透测试
.then(res => {
    console.log(res);
    return new _Promise((resolve, reject) => {
        resolve(3);      // 返回Promise测试
    })
})
.then(res => {
    console.log(res);
    throw new Error('reject测试')   // reject测试
})
.then(() => { }, err => {
    console.log(err);
})
// 输出:1,2,3,Error: reject测试

至此,已经根据原生实现了一个自己的Promise

完整代码:
const PENDING = 'pending';
const FULLFILLED = 'fullfilled';
const REJECTED = 'rejected';

function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {
        throw Error('不能返回自身');
    }
    if (x instanceof _Promise) {
        if (x.status === PENDING) {
            x.then(
                y => resolvePromise(promise2, y, resolve, reject),
                reject
            )
        } else if (x.status === FULLFILLED) {
            resolve(x.value);
        } else {
            reject(x.value);
        }
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        let then = null;
        try {
            then = x.then;
        } catch (error) {
            reject(error);
        }
        if (typeof then === 'function') {
            let called = false;
            try {
                then.call(
                    x,
                    res => {
                        if (called) {
                            return;
                        }
                        called = true;
                        resolvePromise(promise2, res, resolve, reject);
                    },
                    error => {
                        if (called) {
                            return;
                        }
                        called = true;
                        reject(error);
                    }
                )
            } catch (error) {
                if (called) {
                    return;
                }
                called = true;
                reject(error);
            }
        } else {
            resolve(x);
        }
    } else {
        resolve(x);
    }
}

class _Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = null;
        this.fullfilledCallbacks = [];
        this.rejectedCallbacks = [];

        try {
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
            this.reject(error);
        }
    }
    resolve(value) {
        if (this.status === PENDING) {
            setTimeout(() => {
                this.status = FULLFILLED;
                this.value = value;
                this.fullfilledCallbacks.forEach(callback => callback(value));
            })
        }
    }

    reject(reason) {
        if (this.status === PENDING) {
            setTimeout(() => {
                this.status = REJECTED;
                this.value = reason;
                this.rejectedCallbacks.forEach(callback => callback(reason));
            })

        }
    }

    then(onFullfilled, onRejected) {
        onFullfilled = typeof onFullfilled === 'function' ? onFullfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw Error(error) }

        let promise2 = new _Promise((resolve, reject) => {
            if (this.status === PENDING) {
                this.fullfilledCallbacks.push(() => {
                    try {
                        let x = onFullfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
                this.rejectedCallbacks.push(() => {
                    try {
                        let x = onRejected(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
            }

            if (this.status === FULLFILLED) {
                setTimeout(() => {
                    try {
                        let x = onFullfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
            }

            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
            }
        });
        return promise2;
    }
}

本文参考:https://juejin.cn/post/7043758954496655397

更详细、更完整代码(包含注释)可以参考以上连接

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant