Promise实现
Promise是JavaScript中处理异步操作的重要概念,它提供了一种优雅的方式来处理异步代码,避免了回调地狱。本文件将详细介绍Promise的实现原理和代码实现。
核心概念
什么是Promise?
Promise是一个对象,它代表了一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态:
- pending:初始状态,既不是成功,也不是失败状态
- fulfilled:操作成功完成
- rejected:操作失败
Promise的特点
- 状态一旦改变,就不会再变:Promise的状态只能从pending变为fulfilled,或者从pending变为rejected,一旦状态改变,就不会再变
- 链式调用:Promise支持链式调用,通过then方法可以处理异步操作的结果
- 错误捕获:Promise支持通过catch方法捕获错误
- Promise.all:可以并行处理多个Promise
- Promise.race:可以处理多个Promise,返回第一个完成的Promise
实现原理
Promise的实现原理基于以下几个核心概念:
- 状态管理:管理Promise的三种状态(pending、fulfilled、rejected)
- 回调队列:存储then和catch方法注册的回调函数
- 异步处理:使用setTimeout等异步方法确保回调函数在Promise状态改变后执行
- 链式调用:then方法返回一个新的Promise,支持链式调用
实现代码
基础版本
class MyPromise {
constructor(executor) {
// 初始化状态
this.state = 'pending';
// 存储结果
this.value = undefined;
// 存储错误
this.reason = undefined;
// 存储成功回调
this.onFulfilledCallbacks = [];
// 存储失败回调
this.onRejectedCallbacks = [];
// 成功回调
const resolve = (value) => {
// 只有状态为pending时才可以改变状态
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(callback => callback(value));
}
};
// 失败回调
const reject = (reason) => {
// 只有状态为pending时才可以改变状态
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 执行所有失败回调
this.onRejectedCallbacks.forEach(callback => callback(reason));
}
};
// 执行executor函数
try {
executor(resolve, reject);
} catch (error) {
// 如果executor执行出错,直接reject
reject(error);
}
}
// then方法
then(onFulfilled, onRejected) {
// 如果onFulfilled不是函数,默认返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// 如果onRejected不是函数,默认抛出error
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回一个新的Promise
const promise2 = new MyPromise((resolve, reject) => {
// 处理fulfilled状态
if (this.state === 'fulfilled') {
// 使用setTimeout确保回调函数异步执行
setTimeout(() => {
try {
// 执行onFulfilled回调
const x = onFulfilled(this.value);
// 处理回调返回值
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调执行出错,reject
reject(error);
}
}, 0);
}
// 处理rejected状态
if (this.state === 'rejected') {
// 使用setTimeout确保回调函数异步执行
setTimeout(() => {
try {
// 执行onRejected回调
const x = onRejected(this.reason);
// 处理回调返回值
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调执行出错,reject
reject(error);
}
}, 0);
}
// 处理pending状态
if (this.state === 'pending') {
// 将回调函数存储到队列中
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
// 处理回调返回值
resolvePromise(promise2, x, resolve, reject) {
// 如果promise2和x是同一个对象,抛出错误
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 如果x是Promise对象
if (x instanceof MyPromise) {
x.then(
value => this.resolvePromise(promise2, value, resolve, reject),
reason => reject(reason)
);
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 如果x是对象或函数
let called = false;
try {
const then = x.then;
if (typeof then === 'function') {
// 如果x有then方法,将其视为Promise
then.call(
x,
value => {
if (called) return;
called = true;
this.resolvePromise(promise2, value, resolve, reject);
},
reason => {
if (called) return;
called = true;
reject(reason);
}
);
} else {
// 如果x没有then方法,直接resolve
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// 如果x是基本类型,直接resolve
resolve(x);
}
}
// catch方法
catch(onRejected) {
return this.then(null, onRejected);
}
// finally方法
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason })
);
}
// 静态方法resolve
static resolve(value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
// 静态方法reject
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
// 静态方法all
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(
value => {
results[i] = value;
count++;
if (count === promises.length) {
resolve(results);
}
},
reason => {
reject(reason);
}
);
}
});
}
// 静态方法race
static race(promises) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(
value => {
resolve(value);
},
reason => {
reject(reason);
}
);
}
});
}
// 静态方法allSettled
static allSettled(promises) {
return new MyPromise((resolve) => {
const results = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(
value => {
results[i] = { status: 'fulfilled', value };
count++;
if (count === promises.length) {
resolve(results);
}
},
reason => {
results[i] = { status: 'rejected', reason };
count++;
if (count === promises.length) {
resolve(results);
}
}
);
}
});
}
// 静态方法any
static any(promises) {
return new MyPromise((resolve, reject) => {
const errors = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
MyPromise.resolve(promises[i]).then(
value => {
resolve(value);
},
reason => {
errors[i] = reason;
count++;
if (count === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
}
});
}
}使用示例
基本使用
// 创建一个Promise
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
// 处理成功
promise.then(value => {
console.log(value); // 输出: 成功
});错误处理
// 创建一个Promise
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject('失败');
}, 1000);
});
// 处理失败
promise.catch(reason => {
console.log(reason); // 输出: 失败
});链式调用
// 创建一个Promise
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
// 链式调用
promise
.then(value => {
console.log(value); // 输出: 1
return value + 1;
})
.then(value => {
console.log(value); // 输出: 2
return value + 1;
})
.then(value => {
console.log(value); // 输出: 3
});Promise.all
// 创建多个Promise
const promise1 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 1');
}, 1000);
});
const promise2 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 2');
}, 2000);
});
const promise3 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 3');
}, 1500);
});
// 使用Promise.all
MyPromise.all([promise1, promise2, promise3]).then(values => {
console.log(values); // 输出: ['Promise 1', 'Promise 2', 'Promise 3']
});Promise.race
// 创建多个Promise
const promise1 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 1');
}, 1000);
});
const promise2 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 2');
}, 500);
});
const promise3 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 3');
}, 1500);
});
// 使用Promise.race
MyPromise.race([promise1, promise2, promise3]).then(value => {
console.log(value); // 输出: 'Promise 2'
});Promise.allSettled
// 创建多个Promise
const promise1 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 1');
}, 1000);
});
const promise2 = new MyPromise((_, reject) => {
setTimeout(() => {
reject('Promise 2 failed');
}, 500);
});
const promise3 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 3');
}, 1500);
});
// 使用Promise.allSettled
MyPromise.allSettled([promise1, promise2, promise3]).then(results => {
console.log(results);
/* 输出:
[
{ status: 'fulfilled', value: 'Promise 1' },
{ status: 'rejected', reason: 'Promise 2 failed' },
{ status: 'fulfilled', value: 'Promise 3' }
]
*/
});Promise.any
// 创建多个Promise
const promise1 = new MyPromise((_, reject) => {
setTimeout(() => {
reject('Promise 1 failed');
}, 1000);
});
const promise2 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 2');
}, 500);
});
const promise3 = new MyPromise((_, reject) => {
setTimeout(() => {
reject('Promise 3 failed');
}, 1500);
});
// 使用Promise.any
MyPromise.any([promise1, promise2, promise3]).then(value => {
console.log(value); // 输出: 'Promise 2'
});面试常见问题
1. 什么是Promise?它的状态有哪些?
答案示例: Promise是JavaScript中处理异步操作的重要概念,它代表了一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态:
- pending:初始状态,既不是成功,也不是失败状态
- fulfilled:操作成功完成
- rejected:操作失败
Promise的状态一旦改变,就不会再变。
2. 如何实现一个Promise?
答案示例: 实现一个Promise需要以下几个核心部分:
- 状态管理:管理Promise的三种状态(pending、fulfilled、rejected)
- 回调队列:存储then和catch方法注册的回调函数
- 异步处理:使用setTimeout等异步方法确保回调函数在Promise状态改变后执行
- 链式调用:then方法返回一个新的Promise,支持链式调用
- 错误捕获:catch方法用于捕获错误
- 静态方法:实现resolve、reject、all、race等静态方法
具体实现代码可以参考上面的基础版本。
3. Promise.all和Promise.race的区别是什么?
答案示例: Promise.all和Promise.race都是Promise的静态方法,它们的区别在于:
- Promise.all:接收一个Promise数组,返回一个新的Promise,当所有Promise都成功时,返回的Promise才会成功,结果是所有Promise的结果组成的数组;当任何一个Promise失败时,返回的Promise就会失败,失败原因是第一个失败的Promise的原因。
- Promise.race:接收一个Promise数组,返回一个新的Promise,当任何一个Promise完成(成功或失败)时,返回的Promise就会完成,结果是第一个完成的Promise的结果。
4. 如何处理Promise的错误?
答案示例: 处理Promise的错误有以下几种方法:
- 使用catch方法:Promise的catch方法可以捕获前面所有Promise的错误。
promise
.then(value => {
console.log(value);
})
.catch(reason => {
console.log(reason);
});- 在then方法中处理错误:then方法的第二个参数可以处理错误。
promise.then(
value => {
console.log(value);
},
reason => {
console.log(reason);
}
);- 使用try-catch:在async函数中,可以使用try-catch捕获Promise的错误。
async function handlePromise() {
try {
const value = await promise;
console.log(value);
} catch (error) {
console.log(error);
}
}5. Promise的链式调用是如何实现的?
答案示例: Promise的链式调用是通过then方法返回一个新的Promise实现的。具体来说:
- 当调用Promise的then方法时,它会返回一个新的Promise对象
- 这个新的Promise对象的状态由then方法中回调函数的返回值决定
- 如果回调函数返回一个值,新的Promise会以该值为结果变为fulfilled状态
- 如果回调函数抛出一个错误,新的Promise会以该错误为原因变为rejected状态
- 如果回调函数返回一个Promise,新的Promise会等待该Promise完成,然后以相同的结果或错误改变状态
这种机制使得Promise可以通过链式调用的方式处理一系列异步操作,避免了回调地狱。
总结
Promise是JavaScript中处理异步操作的重要概念,它提供了一种优雅的方式来处理异步代码,避免了回调地狱。Promise有三种状态:pending、fulfilled和rejected,状态一旦改变,就不会再变。
实现一个Promise需要管理状态、存储回调队列、处理异步操作、支持链式调用和错误捕获。通过学习Promise的实现原理,我们可以更好地理解和使用Promise,提高异步代码的质量和可维护性。
Promise的静态方法(如Promise.all、Promise.race、Promise.allSettled、Promise.any)提供了处理多个Promise的便捷方式,可以根据不同的场景选择合适的方法。
通过学习和使用Promise,你将能够更好地处理异步操作,写出更加优雅和可维护的JavaScript代码,为面试和工作做好准备。