文章目录
1、概述
Promise
是JavaScript
中用于处理异步操作的一种方式。它提供了一种简洁且强大的方法来处理异步代码,避免了方法回调。本文将详细讲解如何从零开始手写一个Promise
,帮助您深入理解其工作原理。
Promise
有三种状态:
Pending
(待定):初始状态,既不是成功也不是失败。Fulfilled
(已兑现):表示异步操作成功完成,并返回了一个成功值。Rejected
(已拒绝):表示异步操作失败,并返回了一个错误原因。
转换状态如下:
- 从
Pending
状态可以转换成Fulfilled
状态。 - 从
Pending
状态可以转换成Rejected
状态。 - 一旦转换到
Fulfilled
或Rejected
状态,Promise
的状态就不可再改变。
2、常用方法
-
Promise.resolve()
:将给定的值转换为一个Promise
。如果该值本身就是一个Promise
,那么该Promise
将被返回;如果该值是一个thenable
对象,Promise.resolve()
将调用其then()
方法及其两个回调函数;否则,返回的Promise
将会以该值兑现。 -
Promise.reject()
:返回一个已拒绝(rejected
)的Promise
对象,拒绝原因为给定的参数。 -
Promise.all()
:接受一个Promise
可迭代对象作为输入,并返回一个Promise
。当所有输入的Promise
都被兑现时,返回的Promise
也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何Promise
被拒绝,则返回的Promise
将被拒绝,并带有第一个被拒绝的原因。 -
Promise.any()
:将一个Promise
可迭代对象作为输入,并返回一个Promise
。当输入的任何一个Promise
兑现时,这个返回的Promise
将会兑现,并返回第一个兑现的值。当所有输入Promise
都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的AggregateError
拒绝。 -
Promise.race()
:接受一个Promise
可迭代对象作为输入,并返回一个Promise
。这个返回的Promise
会随着第一个Promise
的敲定而敲定。 -
Promise.allSettled()
:将一个Promise
可迭代对象作为输入,并返回一个单独的Promise
。当所有输入的Promise
都已敲定时(包括传入空的可迭代对象时),返回的Promise
将被兑现,并带有描述每个Promise
结果的对象数组。
3、手写Promise
3.1、基本结构
首先,我们需要定义一个Promise
类,并在其构造函数中初始化一些基本属性。
// 定义一个MyPromise类
class MyPromise {
constructor(executor) {
// 初始状态为pending
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的原因
this.reason = undefined;
// 成功回调函数数组
this.onFulfilledCallbacks = [];
// 失败回调函数数组
this.onRejectedCallbacks = [];
// resolve函数,用于将Promise状态从pending变为fulfilled,并记录成功的值
const resolve = value => {
// 只有在pending状态下才进行状态转变并将成功值赋值
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 执行所有成功回调函数
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// reject函数,用于将Promise状态从pending变为rejected,并记录失败的原因
const reject = reason => {
// 只有在pending状态下才进行状态转变并将原因赋值给失败的值
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 执行所有失败回调函数
this.onRejectedCallbacks.forEach(fn => fn());
}
};
// 执行executor函数,并将resolve和reject函数作为参数传入
try {
executor(resolve, reject);
} catch (err) {
// 如果executor函数执行出错,直接调用reject函数
reject(err);
}
}
}
3.2、then 方法
then
方法用于为Promise
实例添加处理成功和失败的回调函数。
MyPromise.prototype.then = function(onFulfilled, onRejected) {
// 设置默认回调函数,确保函数类型,如果没有提供则使用默认处理函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 创建新的Promise,用于链式调用
let promise2 = new MyPromise((resolve, reject) => {
// 如果状态为fulfilled,执行成功回调。如果状态为rejected,执行失败回调
if (this.state === 'fulfilled' || this.state === 'rejected') {
setTimeout(() => {
try {
// 获取成功回调的返回值
let result = this.state === 'fulfilled' ? onFulfilled(this.value) : onRejected(this.reason);
// 处理返回值以确定promise2的状态
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
// 如果执行成功回调过程中出错,直接reject
reject(e);
}
}, 0);
}
// 如果状态为pending,将回调函数存储起来
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
// 获取成功回调的返回值
let x = onFulfilled(this.value);
// 处理返回值以确定promise2的状态
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
// 如果执行成功回调过程中出错,直接reject
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
// 获取失败回调的返回值
let x = onRejected(this.reason);
// 处理返回值以确定promise2的状态
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
// 如果执行失败回调过程中出错,直接reject
reject(e);
}
}, 0);
});
}
});
// 返回新的Promise实例,实现链式调用
return promise2;
};
3.3、resolvePromise 方法
resolvePromise
方法用于处理then
方法中返回的结果,以决定新的Promise
的状态。
function resolvePromise(promise2, x, resolve, reject) {
// 如果promise2和x相等,抛出TypeError防止死循环
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
// 如果x是对象或函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 取出x的then方法
let then = x.then;
// 如果then是函数,调用then,传入resolvePromise和reject函数
if (typeof then === 'function') {
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(r);
});
} else {
// 如果then不是函数,以x为值fulfill promise2
resolve(x);
}
} catch (e) {
// 如果取then方法出错,直接reject
if (called) return;
called = true;
reject(e);
}
} else {
// 如果x不是对象或函数,以x为值fulfill promise2
resolve(x);
}
}
3.4、catch 方法
catch
方法是then
方法的一个快捷方式,用于处理Promise
中的错误。
MyPromise.prototype.catch = function(onRejected) {
// catch方法其实就是调用then方法,但只传入失败回调
return this.then(null, onRejected);
};
3.5、finally 方法
finally
方法用于在Promise
执行结束后,无论结果是成功还是失败,都会执行的回调函数。
MyPromise.prototype.finally = function(callback) {
// finally方法接受一个回调函数,并在Promise结束时调用
return this.then(
value => {
// 调用回调函数,并在它执行完毕后返回原值
return MyPromise.resolve(callback()).then(() => value);
},
reason => {
// 调用回调函数,并在它执行完毕后抛出原错误
return MyPromise.resolve(callback()).then(() => { throw reason });
}
);
};
3.6、resolve 和 reject 方法
resolve
方法用于快速创建一个成功的Promise
,reject
方法用于快速创建一个失败的Promise
。
MyPromise.prototype.resolve = function(value) {
// 直接返回一个新的成功状态的Promise
return new MyPromise((resolve, reject) => {
resolve(value);
});
};
MyPromise.prototype.reject = function(reason) {
// 直接返回一个新的失败状态的Promise
return new MyPromise((resolve, reject) => {
reject(reason);
});
};
3.7、all 方法
all
方法用于将多个Promise
实例包装成一个新的Promise
实例,只有所有Promise
实例都成功时,新Promise
实例才会成功。
MyPromise.prototype.all = function(promises) {
// 返回一个新的Promise
return new MyPromise((resolve, reject) => {
// 存储所有Promise的结果
let resultArray = [];
// 记录已完成的Promise数量
let count = 0;
// 处理单个Promise的结果
function processResult(index, data) {
resultArray[index] = data;
count++;
// 如果所有Promise都完成,resolve新的Promise
if (count === promises.length) {
resolve(resultArray);
}
}
// 遍历所有Promise,处理其结果
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
processResult(i, data);
}, reject);
}
});
};
3.8、race 方法
race
方法用于将多个Promise
实例包装成一个新的Promise
实例,只要其中一个Promise
实例率先完成,新Promise
实例就会完成。
MyPromise.prototype.race = function(promises) {
// 返回一个新的Promise
return new MyPromise((resolve, reject) => {
// 遍历所有Promise,任意一个Promise完成就resolve/reject新的Promise
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
};
3.9、any方法
any
方法用于将多个Promise
实例包装成一个新的Promise
实例,只要其中一个Promise
实例成功,新Promise
实例就会成功;如果所有的Promise
实例都失败,新Promise
实例才会失败。
// any方法,任意一个Promise成功则返回成功,所有Promise失败则返回失败
MyPromise.prototype.any = function(promises) {
return new MyPromise((resolve, reject) => {
let errors = [];
let rejectedCount = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, error => {
errors[i] = error;
rejectedCount++;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
}
});
}
3.10、allSettled方法
allSettled
方法用于将多个Promise
实例包装成一个新的Promise
实例,当所有的Promise
实例都已完成(无论是成功还是失败)时,新Promise
实例才会完成,并且返回一个对象数组,描述每个Promise
的结果。
// allSettled方法,所有Promise都完成时返回包含每个Promise结果的数组
MyPromise.prototype.allSettled = function(promises) {
return new MyPromise((resolve) => {
let resultArray = [];
let count = 0;
function processResult(index, status, value) {
resultArray[index] = { status, value };
count++;
if (count === promises.length) {
resolve(resultArray);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(
value => processResult(i, 'fulfilled', value),
reason => processResult(i, 'rejected', reason)
);
}
});
}
3.11、完整代码
class MyPromise {
constructor(executor) {
// 初始状态为pending
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的原因
this.reason = undefined;
// 成功回调函数数组
this.onFulfilledCallbacks = [];
// 失败回调函数数组
this.onRejectedCallbacks = [];
// resolve函数,用于将Promise状态从pending变为fulfilled,并记录成功的值
const resolve = value => {
// 只有在pending状态下才进行状态转变
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 执行所有成功回调函数
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// reject函数,用于将Promise状态从pending变为rejected,并记录失败的原因
const reject = reason => {
// 只有在pending状态下才进行状态转变
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 执行所有失败回调函数
this.onRejectedCallbacks.forEach(fn => fn());
}
};
// 执行executor函数,并将resolve和reject函数作为参数传入
try {
executor(resolve, reject);
} catch (err) {
// 如果executor函数执行出错,直接调用reject函数
reject(err);
}
}
// then方法,用于为Promise实例添加处理成功和失败的回调函数
then(onFulfilled, onRejected) {
// 设置默认回调函数,确保函数类型,如果没有提供则使用默认处理函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 创建新的Promise,用于链式调用
let promise2 = new MyPromise((resolve, reject) => {
// 如果状态为fulfilled,执行成功回调,如果状态为rejected,执行失败回调
if (this.state === 'fulfilled' || this.state === 'rejected') {
setTimeout(() => {
try {
// 获取成功回调的返回值
let result = this.state === 'fulfilled' ? onFulfilled(this.value) : onRejected(this.reason);
// 处理返回值以确定promise2的状态
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
// 如果执行成功回调过程中出错,直接reject
reject(e);
}
}, 0);
}
// 如果状态为pending,将回调函数存储起来
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
// 获取成功回调的返回值
let result = onFulfilled(this.value);
// 处理返回值以确定promise2的状态
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
// 如果执行成功回调过程中出错,直接reject
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
// 获取失败回调的返回值
let result = onRejected(this.reason);
// 处理返回值以确定promise2的状态
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
// 如果执行失败回调过程中出错,直接reject
reject(e);
}
}, 0);
});
}
});
// 返回新的Promise实例,实现链式调用
return promise2;
}
// catch方法是then方法的一个快捷方式,用于处理Promise中的错误
catch(onRejected) {
// catch方法其实就是调用then方法,但只传入失败回调
return this.then(null, onRejected);
}
// finally方法用于在Promise执行结束后,无论结果是成功还是失败,都会执行的回调函数
finally(callback) {
// finally方法接受一个回调函数,并在Promise结束时调用
return this.then(
value => {
// 调用回调函数,并在它执行完毕后返回原值
return MyPromise.resolve(callback()).then(() => value);
},
reason => {
// 调用回调函数,并在它执行完毕后抛出原错误
return MyPromise.resolve(callback()).then(() => { throw reason });
}
);
}
// resolve方法用于快速创建一个成功的Promise
static resolve(value) {
// 直接返回一个新的成功状态的Promise
return new MyPromise((resolve, reject) => {
resolve(value);
});
}
// reject方法用于快速创建一个失败的Promise
static reject(reason) {
// 直接返回一个新的失败状态的Promise
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
// all方法用于将多个Promise实例包装成一个新的Promise实例,只有所有Promise实例都成功时,新Promise实例才会成功
static all(promises) {
// 返回一个新的Promise
return new MyPromise((resolve, reject) => {
// 存储所有Promise的结果
let resultArray = [];
// 记录已完成的Promise数量
let count = 0;
// 处理单个Promise的结果
function processResult(index, data) {
resultArray[index] = data;
count++;
// 如果所有Promise都完成,resolve新的Promise
if (count === promises.length) {
resolve(resultArray);
}
}
// 遍历所有Promise,处理其结果
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
processResult(i, data);
}, reject);
}
});
}
// race方法用于将多个Promise实例包装成一个新的Promise实例,只要其中一个Promise实例率先完成,新Promise实例就会完成
static race(promises) {
// 返回一个新的Promise
return new MyPromise((resolve, reject) => {
// 遍历所有Promise,任意一个Promise完成就resolve/reject新的Promise
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
}
// any方法,任意一个Promise成功则返回成功,所有Promise失败则返回失败
static any(promises) {
return new MyPromise((resolve, reject) => {
let errors = [];
let rejectedCount = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, error => {
errors[i] = error;
rejectedCount++;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
}
});
}
}
// resolvePromise方法用于处理then方法中返回的结果,以决定新的Promise的状态
function resolvePromise(promise2, x, resolve, reject) {
// 如果promise2和x相等,抛出TypeError防止死循环
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
// 如果x是对象或函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 取出x的then方法
let then = x.then;
// 如果then是函数,调用then,传入resolvePromise和reject函数
if (typeof then === 'function') {
// 将this指向x,并调用then()
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if (called) return;
called = true;
reject(err);
});
} else {
// 如果then不是函数,以x为值fulfill promise2
resolve(x);
}
} catch (err) {
// 如果取then方法出错,直接reject
if (called) return;
called = true;
reject(err);
}
} else {
// 如果x不是对象或函数,以x为值fulfill promise2
resolve(x);
}
}
4、结语
通过手写Promise
,我们深入了解了其内部工作原理。希望这篇技术文档对您理解Promise
有所帮助。如果在实践中遇到问题,建议参考ES6标准中的Promise
规范进行进一步学习。