Appearance
Promise 实现原理
前言
Promise是JavaScript中处理异步操作的重要机制,它提供了一种更优雅的方式来处理回调。本文将全面介绍Promise的概念、用法及实现原理。
一、Promise基础
1.1 什么是Promise?
Promise是一个代表异步操作最终完成或失败的对象。它有三种状态:
- pending(进行中)
- fulfilled(已成功)
- rejected(已失败)
javascript
// 基础Promise示例
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
resolve('成功');
} else {
reject('失败');
}
}, 1000);
});
1.2 Promise的特点
- 状态不可逆
- 支持链式调用
- 错误可以被捕获
二、Promise的使用
2.1 基本方法
then()
javascript
// 处理成功和失败
promise.then(
result => console.log('成功:', result),
error => console.log('失败:', error)
);
// 只处理成功
promise.then(result => console.log('成功:', result));
catch()
javascript
// 处理错误
promise
.then(result => console.log('成功:', result))
.catch(error => console.log('错误:', error));
finally()
javascript
// 无论成功失败都会执行
promise
.then(result => console.log('成功:', result))
.catch(error => console.log('错误:', error))
.finally(() => console.log('完成'));
2.2 静态方法
Promise.all()
javascript
// 所有Promise都成功才成功
const promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
];
Promise.all(promises)
.then(results => console.log('全部完成:', results))
.catch(error => console.log('有一个失败:', error));
Promise.race()
javascript
// 返回最先完成的Promise结果
const promise1 = new Promise(resolve => setTimeout(() => resolve('一秒'), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve('两秒'), 2000));
Promise.race([promise1, promise2])
.then(result => console.log('最快完成:', result));
Promise.allSettled()
javascript
// 等待所有Promise完成,无论成功失败
const promises = [
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
];
Promise.allSettled(promises)
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
三、实际应用场景
3.1 异步请求处理
javascript
// 封装fetch请求
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
}
// 使用async/await
async function getData() {
try {
const data = await fetchData('https://api.example.com/data');
console.log(data);
} catch (error) {
console.error(error);
}
}
3.2 并发控制
javascript
// 限制并发请求数量
async function limitConcurrency(tasks, limit) {
const results = [];
const executing = new Set();
for (const task of tasks) {
const promise = Promise.resolve().then(() => task());
results.push(promise);
executing.add(promise);
const clean = () => executing.delete(promise);
promise.then(clean, clean);
if (executing.size >= limit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
// 使用示例
const tasks = Array(10).fill(() => new Promise(resolve =>
setTimeout(() => resolve(Math.random()), 1000)
));
limitConcurrency(tasks, 3)
.then(results => console.log('所有任务完成:', results));
四、Promise实现原理
4.1 简单实现
javascript
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error };
return new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
});
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
});
}
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
});
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
五、面试常见问题
5.1 Promise和回调的区别?
javascript
// 回调地狱
asyncOperation1(result1 => {
asyncOperation2(result1, result2 => {
asyncOperation3(result2, result3 => {
console.log(result3);
});
});
});
// Promise链式调用
asyncOperation1()
.then(result1 => asyncOperation2(result1))
.then(result2 => asyncOperation3(result2))
.then(result3 => console.log(result3))
.catch(error => console.error(error));
5.2 如何实现Promise.all?
javascript
function promiseAll(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('promises must be an array'));
}
const results = [];
let completed = 0;
if (promises.length === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(result => {
results[index] = result;
completed++;
if (completed === promises.length) {
resolve(results);
}
})
.catch(reject);
});
});
}
六、最佳实践建议
- 总是使用catch处理错误
- 避免嵌套Promise
- 合理使用Promise.all和Promise.race
- 使用async/await简化Promise操作
- 注意Promise的性能影响
javascript
// 不好的写法
promise
.then(result => {
return new Promise(resolve => {
resolve(result);
});
});
// 好的写法
promise
.then(result => result);
// 使用async/await
async function example() {
try {
const result = await promise;
return result;
} catch (error) {
console.error(error);
}
}
总结
Promise是现代JavaScript异步编程的基础,掌握Promise对于编写高质量的异步代码至关重要。通过合理使用Promise,我们可以:
- 有效避免回调地狱
- 更优雅地处理异步操作
- 更好地处理错误
- 实现更复杂的异步流程控制
希望本文能帮助你更好地理解和使用Promise!