前端面试?这份手撸Promise请你收下
前言
现在很多大厂面试前端都会要求能够手动的写出一个Promise
,所以这里整理了一份手写的Promise
。
绝对详细,功能绝对强大。如果你不了解Promise
的基本使用,那么本篇文章可能不太适合你,如果你对Promise
有过一些了解,那么这篇文章绝对是你进阶的好帮手。
除开catch()
以及finally()
和allSettled
接口没实现之外,其他的所有原生Promise
支持的功能此手写的Promise
都支持。
书写Promise
的难度其实就在于then()
方法的链式调用以及值穿透传递,其他的其实都还好。
让这篇文章滚进你的收藏夹吧!
Promise状态实现
在原生Promise
中具有三种状态,分别是
pending
:未解决状态
fulfilled
:已解决状态
rejected
:解决失败状态
所以第一步,要先实现这三种状态。
并且在原生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执行函数
原生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状态限制
当前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;
}
}
}
Promise执行异常
在执行函数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;
}
}
}
then方法基础实现
原生的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方法参数优化
上面已经说过,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方法异常捕获
当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);
}
}
}
}
then方法异步执行
在原生的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,
});
}
}
}
异步执行函数的then异常捕获
上面我们对同步执行函数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);
}
}
});
}
}
}
then方法链式操作
对于原生的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.不支持类型限制
接下来继续对代码做出优化调整。
then中返回普通值
在原生的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中的异常传递
在上面的代码中,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>
then穿透功能实现
在原生的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
}
}
});
}
});
}
}
then返回Promise
原生的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的代码优化
可以观察到上面的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返回类型限制
我们都知道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); // 向下传递异常
}
}
}
resolve与reject实现
使用 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);
});
}
}
all与race实现
使用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); // 同上
})
})
})
}
}
前端面试?这份手撸Promise请你收下的更多相关文章
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- 2019前端面试系列——JS高频手写代码题
实现 new 方法 /* * 1.创建一个空对象 * 2.链接到原型 * 3.绑定this值 * 4.返回新对象 */ // 第一种实现 function createNew() { let obj ...
- 这份前端面试小册子dog cheng带来啦~
写在前面 没有错,就是我啦dog cheng,好久不见,从17年在博客园写下第一篇文章,转身间已然两年,从大二到现在的大四预备毕业生,我仍然在这条道路上前进.秋招早已经结束,在拿到用友,滴滴的offe ...
- 前端面试手写代码——call、apply、bind
1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...
- Web前端面试宝典(最新)
第一部分:HTML问答题 1.简述一下你对HTML语义化的理解? 用正确的标签做正确的事情. html语义化让页面的内容结构化,结构更清晰,便于对浏览器.搜索引擎解析;即使在没有样式CSS情况下也 ...
- 2019前端面试系列——Vue面试题
Vue 双向绑定原理 mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter.getter,在数 ...
- 2016年Web前端面试题目汇总
转载: 2016年Web前端面试题目汇总 以下是收集一些面试中经常会遇到的经典面试题以及自己面试过程中未解决的问题,通过对知识的整理以及经验的总结,重新巩固自身的前端基础知识,如有错误或更好的答案,欢 ...
- web前端面试试题总结---javascript篇
JavaScript 介绍js的基本数据类型. Undefined.Null.Boolean.Number.String. ECMAScript 2015 新增:Symbol(创建后独一无二且不可变的 ...
- 2017web前端面试总结
2017web前端面试总结 从今年3月份开始面试笔试找实习找校招到现在也半年多了,拿到了不少offer,也有了自己的一点心得体会,这里写出来分享一下,拙见勿喷. 注意一下,以下的观点仅代表我个人的体会 ...
随机推荐
- GitHub和码云gitee及远程仓库管理
目录 备注: 知识点 GitHub 码云(gitee.com) gitee的使用 本地版本库关联多个远程库 备注: 本文参考于廖雪峰老师的博客Git教程.依照其博客进行学习和记录,感谢其无私分享,也欢 ...
- Linux中profile和bashrc的区别
profile主要设置系统环境参数(可类比为Windows的系统环境变量),如$PATH /etc/profile ~/.bash_profile bashrc主要用来设置bash命令,如命令别名,a ...
- C#计算数组的算术平均数、几何平均数、调和平均数、平方平均数和中位数
1.函数实现 0)打印数组 /// <summary> /// 打印数组 /// </summary> /// <param name="arr"&g ...
- Flutter + Android 混合开发
JIT (Just In Time) 即时编译器, 边执行边编译 程序运行时,JIT 编译器选择将最频繁执行的方法编译成本地代码.运行时才进行本地代码编译而不是在程序运行前进行编译 AOT可以理解为“ ...
- 完全卸载MySQL完整图文流程
想把mlsql卸载了重装,看了许多文章试了很多方法都没办法完全卸载,直到看到了这篇文章, 可以完全卸载mysql,在这里谢谢博主,也拿出来分享给大家 原文链接:https://blog.csdn.ne ...
- .NET Core + K8S + Loki 玩转日志聚合
1. Intro 最近在了解日志聚合系统,正好前几天看到一篇文章<用了日志系统新贵Loki,ELK突然不香了!>,所以就决定动手体验一下.本文就带大家快速了解下Loki,并简单介绍.NET ...
- laravel 上线部署最佳实践
nginx 配置 listen 80 default_server; server_name xxxx; index index.php index.html; 优先 index.php ro ...
- 扯扯Java中的锁
前言 又过去了一个周末,最近陆陆续续的看了<并发编程的艺术>一书,对锁有不少感悟,这次就聊聊Java中的锁事.本文纯粹是漫谈,想到哪说到哪,但准确性肯定会保证,倘若有不正确之处,还请交流指 ...
- PHP cos() 函数
实例 返回不同数的余弦: <?phpecho(cos(3) . "<br>");echo(cos(-3) . "<br>");ec ...
- 3.28 省选模拟赛 染色 LCT+线段树
发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...