如今不少大厂面试前端都会要求可以手动的写出一个Promise
,因此这里整理了一份手写的Promise
。前端
绝对详细,功能绝对强大。若是你不了解Promise
的基本使用,那么本篇文章可能不太适合你,若是你对Promise
有过一些了解,那么这篇文章绝对是你进阶的好帮手。面试
除开catch()
以及finally()
和allSettled
接口没实现以外,其余的全部原生Promise
支持的功能此手写的Promise
都支持。数组
书写Promise
的难度其实就在于then()
方法的链式调用以及值穿透传递,其余的其实都还好。promise
让这篇文章滚进你的收藏夹吧!异步
在原生Promise
中具备三种状态,分别是函数
pending
:未解决状态优化
fulfilled
:已解决状态this
rejected
:解决失败状态线程
因此第一步,要先实现这三种状态。code
而且在原生Promise
中具备value
用于记录resolve()
与reject()
中的值用于传递给then()
方法。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始为准备状态 this.value = null; // 初始值 } }
原生Promise
的构造函数中会接收一个executor
参数,该参数当是一个函数。
用于同步的执行当前任务,当任务完成后应该具备resolve()
方法以及reject()
方法来通知then()
方法当前执行任务的执行状态并传递值。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 executor(this.resolve, this.reject); // 传递形参,运行executor函数 } resolve(value) { this.status = MyPromise.FUFILLED; this.value = value; } reject(reason) { this.status = MyPromise.REJECTED; this.value = reason; } }
上面这样写在执行resolve()
以及reject()
时会出现问题,缘由是this
指向为undefiled
(严格模式)。
<script src="./Promise核心.js"></script> <script> "use strict"; let p1 = new MyPromise((resolve, reject) => { resolve("成功") }) console.log(p1); </script>
这是因为咱们在执行函数中调用了resolve()
与reject()
,故this
指向为executor
的函数上下文。
解决这个问题可使用bind()
来改变this
指向。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } resolve(value) { this.status = MyPromise.FUFILLED; this.value = value; } reject(reason) { this.status = MyPromise.REJECTED; this.value = reason; } }
当前Promise
状态只应该改变一次而不能屡次改变,显然咱们上面的代码不能作到这点限制。
<script src="./Promise核心.js"></script> <script> "use strict"; let p1 = new MyPromise((resolve, reject) => { resolve("成功"); reject("失败"); // 对于原生Promise来讲,状态只能改变一次。可是这里却容许两次改变,故是有问题的 }) console.log(p1); // MyPromise {status: "rejected", value: "失败"} </script>
因此这里要对代码加上限制。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } }
在执行函数executor
中可能引起异常,这会让当前的Promise
的状态改变为rejected
。
因此在上面代码基础上须要加入try...catch
进行处理。
当then()
方法捕捉到执行函数executor
中的异常时,可让第二个参数的函数对其异常进行处理,可是咱们目前还没实现then()
,因此直接丢给reject()
便可,当实现then()
时天然会使用到reject()
中传递过来的值。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } }
原生的Promise
状态改变后,能够执行其下的then()
方法,因此咱们须要来封装出一个then()
方法。
then()
方法接收两个函数,第一个函数onFulfilled
用于处理上一个Promise
的fulfilled
状态,第二个函数onRejected
用于处理上一个Promise
的rejected
状态。
而且then()
方法中的这两个函数都应该具备一个形参,用于接收到Promise
的resolve()
或reject()
中传递的值。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } then(onFulfilled, onRejected) { if(this.status == MyPromise.FUFILLED){ // 状态改变时执行 onFulfilled(this.value); } if(this.status == MyPromise.REJECTED){ // 状态改变时执行 onRejected(this.value); } } }
上面已经说过,then()
方法具备两个参数,这两个参数分别对应两个函数用来处理上一个Promsie
的resolve()
与reject()
。
可是在原生Promise
中,这两个方法能够不进行传递,因此咱们须要对上述代码进行优化。
当then()
方法中的某一个参数不为函数时,让它自动建立一个空函数。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } then(onFulfilled, onRejected) { if(typeof onFulfilled != "function"){ // 若是传入的不是一个函数,默认建立空函数 onFulfilled = ()=>{}; } if(typeof onRejected != "function"){ // 若是传入的不是一个函数,默认建立空函数 onRejected = ()=>{}; } if(this.status == MyPromise.FUFILLED){ // 状态改变时执行 onFulfilled(this.value); } if(this.status == MyPromise.REJECTED){ // 状态改变时执行 onRejected(this.value); } } }
当then()
方法中处理fulfilled
状态的函数onFulfilled
或者处理rejected
状态的函数onRejected
在运行时出现异常应该进行捕获而且传递给下一个then()
的处理rejected
状态的函数onRejected
。
这里咱们先让全部的异常都交由当前then()
处理rejected
状态的函数onRejected
,后面再进行优化。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } } } }
在原生的Promise
中,executor
函数是同步执行的,而then()
方法是异步执行故排在同步执行以后。
可是咱们的Promise
却没有作到这一点,下面的实验将说明这个问题
<script src="./Promise核心.js"></script> <script> "use strict"; let p1 = new MyPromise((resolve, reject) => { reject("失败"); }).then( null, error => { console.log(error); // 先打印 失败 } ) console.log("hello,Promise"); // 后打印 hello,Promise </script>
最简单的解决方案就是为then()
中处理成功或处理失败的函数运行外套上一个setTimeout
,让其处理排在线程同步任务执行以后再进行执行。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } }) } } }
此时咱们的代码仍然具备一个问题,即在执行函数executor
中使用setTimeout
时,下面的then()
会进行阻塞。
这是由于当前Promise
状态是pending
而then()
方法中并无对pending
状态进行处理的策略所致使的。
<script src="./Promise核心.js"></script> <script> "use strict"; new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功"); // 同步任务执行完三秒后才会改变当前Promise状态 }, 3000); }).then((success) => { // 可是这里先执行了then,Promise状态为pending,故发生阻塞 console.log(success); // 阻塞了,不打印 }) </script>
既然当前Promise
状态是pending
,3秒后状态才发生改变,那么咱们就能够经过不断的循环来看看它什么时候改变状态。
因此第一步是定义一个执行异步的数组。而后再将then()
中处理正确的函数onFulfilled
与处理错误的函数onRejected
压进去。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled, onRejected, }); } } }
当数组压入完成后,执行函数executor
会去调用resolve()
或者reject()
改变当前Promise
状态。
因此咱们还须要在resolve()
与reject()
方法中对异步的数组处理函数进行调用。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled, onRejected, }); } } }
上面咱们对同步执行函数executor
调用then()
方法中可能出现的异常进行了处理。
就是下面这一段代码。
if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } }) }
可是咱们尚未对异步执行函数executor
调用then()
方法中可能出现的异常进行处理。
if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled, onRejected, }); } }
这会致使下面这样的使用场景出现问题。
<script src="./Promise核心.js"></script> <script> "use strict"; new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功"); }, 3000); }).then((success) => { throw new Error("自定义异常抛出"); // 直接在处理成功状态的函数onFulfilled中抛出了异常,显然是不符合原生Promise的 }); </script>
那么咱们就来加上异常捕获便可,这里仍是先传递给当前then()
处理rejected
状态的函数,后面会作修改。
由于原版Promise
会传递给下一个then()
中处理rejected
状态的函数,而不是当前then()
。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { try { // 异步executor改变状态对其then中的onFulfilled进行异常捕获 onFulfilled(value); } catch (e) { onRejected(e); } }, onRejected: value => { try { // 异步executor改变状态对其then中的onRejected进行异常捕获 onRejected(value); } catch (e) { onRejected(e); } } }); } } }
对于原生的Promise
来说,每个then()
最后返回的都是一个新的Promise
。因此才能达到支持不断的then()
进行链式操做,因此咱们也能够这样作。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } return new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onFulfilled(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 onRejected(this.value); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { try { // 异步executor改变状态对其then中的onFulfilled进行异常捕获 onFulfilled(value); } catch (e) { onRejected(e); } }, onRejected: value => { try { // 异步executor改变状态对其then中的onRejected进行异常捕获 onRejected(value); } catch (e) { onRejected(e); } } }); } }); } }
如今咱们的Promise
已经支持then()
的链式操做了,可是上面代码仍是遗留了几个问题。
1.
then()
尚未返回值,返回普通值该怎么处理,返回一个新的Promise
该怎么处理2.没有异常传递,原生
Promise
中的then()
当抛出异常时应该进行捕获并传递给下一个then()
3.不支持
then()
穿透4.不支持类型限制
接下来继续对代码作出优化调整。
在原生的Promise
中每个then()
所产生的Promise
默认状态都是fulfilled
,若是当前then()
返回是一个值的话那么下一个then()
将接受到该值。
这个也很是简单,代码接收一下每个onFulfilled()
与onRejected()
的返回值就好,并使用resolve()
改变状态为fulfilled
以及将值进行传递给下一个then()
。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } return new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理成功的函数onFulfilled中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 let result = onFulfilled(this.value); resolve(result); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { // then处理失败的函数onRejected中出现异常,交由当前then处理失败的函数onRejected函数进行处理。这个后面会作优化 let result = onRejected(this.value); resolve(result); } catch (e) { onRejected(e); } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { try { // 异步executor改变状态对其then中的onFulfilled进行异常捕获 let result = onFulfilled(value); resolve(result); } catch (e) { onRejected(e); } }, onRejected: value => { try { // 异步executor改变状态对其then中的onRejected进行异常捕获 let result = onRejected(value); resolve(result); } catch (e) { onRejected(e); } } }); } }); } }
这样咱们的then()
就支持返回普通值了。
<script src="./Promise核心.js"></script> <script> "use strict"; new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功"); }, 3000); }).then((success) => { return "hello"; }).then((success)=>{ console.log(success); // hello }); </script>
在上面的代码中,then()
方法里的处理成功函数onFulfilled
以及处理失败函数onRejected
在代码执行时抛出的异常都会统一进行捕获而且传递给当前then()
方法处理失败的函数onRejected
。
这个与原生的Promise
有出入,对于原生Promise
来说应该是传递给下一个then()
进行处理而不是当前then()
。
改动也很是简单,将原来发生异常传递的函数onRejected()
改成reject()
便可,这就是传递给下一个then()
。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => { }; } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => { }; } return new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { let result = onFulfilled(this.value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { let result = onRejected(this.value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { try { let result = onFulfilled(value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } }, onRejected: value => { try { let result = onRejected(value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } } }); } }); } }
<script src="./Promise核心.js"></script> <script> "use strict"; new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功"); }, 3000); }).then((success) => { throw new Error("新错误"); }).then(null, error => { console.log(error); // 上一个then的错误成功由该then接收 }); </script>
在原生的Promise
中是支持then()
的穿透传值的。
<script> "use strict"; new Promise((resolve, reject) => { resolve("成功"); }) .then() // 穿透 .then( success => { console.log(success); // 成功 }, error => { console.log(error); }) </script>
可是咱们的Promise
却不支持。
<script src="./Promise核心.js"></script> <script> "use strict"; new MyPromise((resolve, reject) => { resolve("成功"); }) .then() // 不支持穿透 .then( success => { console.log(success); }, error => { console.log(error); }) </script>
缘由在于若是没有对then()
进行传递参数,那么内部实际上是会建立两个空函数。
咱们只须要在空函数内部返回this.value
便可。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => this.value; // 支持穿透 } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => this.value; // 支持穿透 } return new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { let result = onFulfilled(this.value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { let result = onRejected(this.value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { try { let result = onFulfilled(value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } }, onRejected: value => { try { let result = onRejected(value); resolve(result); } catch (e) { reject(e); // 传递给下一个then } } }); } }); } }
原生的Promise
支持返回一个新的Promise
,可是咱们的Promise
如今还不支持。
其实也很简单,判断一下then()
中两个函数返回的是否是一个新的Promise
,若是是的话则使用其then()
方法将其中resolve()
或reject()
的值进行传递。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => this.value; // 支持穿透 } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => this.value; // 支持穿透 } return new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { let result = onFulfilled(this.value); if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 传递给下一个then } }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 try { let result = onRejected(this.value); if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 传递给下一个then } }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { try { let result = onFulfilled(value); if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 传递给下一个then } }, onRejected: value => { try { let result = onRejected(value); if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 传递给下一个then } } }); } }); } }
能够观察到上面的then()
方法中有不少重复代码,因此咱们须要对重复代码作一下优化。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => this.value; // 支持穿透 } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => this.value; // 支持穿透 } return new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(onFulfilled(this.value), resolve, reject); }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(onRejected(this.value), resolve, reject); }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { this.parse(onFulfilled(value), resolve, reject); }, onRejected: value => { this.parse(onRejected(value), resolve, reject); } }); } }); } parse(result, resolve, reject) { try { if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 向下传递异常 } } }
咱们都知道then()
会建立一个Promise
并返回,可是原生的Promise
不支持then()
将本身建立的Promise
进行返回
<script> "use strict"; let p1 = new Promise((resolve, reject) => { resolve("成功"); }) let p2 = p1.then( // 因为then中的处理成功与处理失败的函数是属于异步执行。因此会先将建立好的Promise对象返回再运行其中的处理成功函数与处理失败函数。 success => { return p2; } ) // Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise> </script>
可是咱们的Promise
还不支持这一点,因此须要改一改代码。
解决的思路也很简单,在运行失败或处理函数时判断一下本次返回的值是否等同于建立的Promise
对象。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => this.value; // 支持穿透 } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => this.value; // 支持穿透 } let promise = new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(promise, onFulfilled(this.value), resolve, reject); }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(promise, onRejected(this.value), resolve, reject); }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { this.parse(promise, onFulfilled(value), resolve, reject); }, onRejected: value => { this.parse(promise, onRejected(value), resolve, reject); } }); } }); return promise; // 同步,先返回。onFulfilled与onRejected因为套了setTimeout,是异步执行。 } parse(promise, result, resolve, reject) { if (promise == result) { throw new TypeError("Chaining cycle detected"); } try { if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 向下传递异常 } } }
使用 Promise.resolve()
方法能够快速的返回一个状态是fulfilled
的Promise
对象。
使用 Promise.reject()
方法能够快速的返回一个状态是rejected
的Promise
对象。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => this.value; // 支持穿透 } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => this.value; // 支持穿透 } let promise = new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(promise, onFulfilled(this.value), resolve, reject); }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(promise, onRejected(this.value), resolve, reject); }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { this.parse(promise, onFulfilled(value), resolve, reject); }, onRejected: value => { this.parse(promise, onRejected(value), resolve, reject); } }); } }); return promise; // 同步,先返回。onFulfilled与onRejected因为套了setTimeout,是异步执行。 } parse(promise, result, resolve, reject) { if (promise == result) { throw new TypeError("Chaining cycle detected"); } try { if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 向下传递异常 } } static resolve(value) { return new MyPromise((resolve, reject) => { if (value instanceof MyPromise) { value.then(resolve, reject); } else { resolve(value); } }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } }
使用Promise.all()
方法能够同时执行多个并行异步操做,好比页面加载时同进获取课程列表与推荐课程。任何一个 Promise
执行失败就会调用 catch
方法,成功后返回 Promise
结果的有序数组。(Ps:咱们这个Promise
没有实现catch
方法)
使用Promise.race()
处理容错异步,和race
单词同样哪一个Promise
快用哪一个,哪一个先返回用哪一个。
class MyPromise { static PENDING = "pending"; static FUFILLED = "fulfilled"; static REJECTED = "rejected"; constructor(executor) { this.status = MyPromise.PENDING; // 初始状态为准备状态 this.value = null; // 初始值 this.callbacks = []; // 若是是一个异步操做,则放入该数组中 try { executor(this.resolve.bind(this), this.reject.bind(this)); // 传递形参,运行executor函数 } catch (e) { this.status = MyPromise.REJECTED; // 异常发生改变状态 this.reject(e); // 记录异常信息 } } resolve(value) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.FUFILLED; this.value = value; this.callbacks.map(callback => { // // 调用处理异步executor里resolve的方法。 callback.onFulfilled(value); }) } } reject(reason) { if (this.status == MyPromise.PENDING) { // 限制 this.status = MyPromise.REJECTED; this.value = reason; this.callbacks.map(callback => { // 调用处理异步executor里reject的方法。 callback.onRejected(reason); }) } } then(onFulfilled, onRejected) { if (typeof onFulfilled != "function") { // 若是传入的不是一个函数,默认建立空函数 onFulfilled = () => this.value; // 支持穿透 } if (typeof onRejected != "function") { // 若是传入的不是一个函数,默认建立空函数 onRejected = () => this.value; // 支持穿透 } let promise = new MyPromise((resolve, reject) => { // 返回一个新的Promise if (this.status == MyPromise.FUFILLED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(promise, onFulfilled(this.value), resolve, reject); }) } if (this.status == MyPromise.REJECTED) { // 状态改变时执行 setTimeout(() => { // 晚于线程同步任务执行 this.parse(promise, onRejected(this.value), resolve, reject); }) } if (this.status == MyPromise.PENDING) { // 若是当前Promise是等待处理状态,则将处理成功的函数与处理失败的函数压入异步数组。 this.callbacks.push({ onFulfilled: value => { this.parse(promise, onFulfilled(value), resolve, reject); }, onRejected: value => { this.parse(promise, onRejected(value), resolve, reject); } }); } }); return promise; // 同步,先返回。onFulfilled与onRejected因为套了setTimeout,是异步执行。 } parse(promise, result, resolve, reject) { if (promise == result) { throw new TypeError("Chaining cycle detected"); } try { if (result instanceof MyPromise) { // 判断是否返回Promise对象 result.then(resolve, reject); } else { resolve(result); // 改变状态并将值交由下一个then接收 } } catch (e) { reject(e); // 向下传递异常 } } static resolve(value) { return new MyPromise((resolve, reject) => { if (value instanceof MyPromise) { value.then(resolve, reject); } else { resolve(value); } }); } static reject(value) { return new MyPromise((resolve, reject) => { reject(value); }); } static all(value) { return new MyPromise((resolve, reject) => { const values = []; // 记录当前有多少promise状态是成功 promise.forEach((promise) => { promise.then(value => { values.push(value); if (values.length == promise.length) { resolve(values); // 若是都成功,当前all返回的promise则状态为fulfilled。 } }, reason => { reject(reason); // 若是有一个promise错误,则当前all返回的promise则为拒绝 }) }); }); } static race(value) { return new MyPromise((resolve, reject) => { value.forEach(promise => { promise.then(value => { // 若是循环中的promise状态为fulfilled,则当前的race建立的promise状态也为resolve resolve(value); }, reason => { reject(value); // 同上 }) }) }) } }