Skip to content

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的特点

  1. 状态不可逆
  2. 支持链式调用
  3. 错误可以被捕获

二、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);
        });
    });
}

六、最佳实践建议

  1. 总是使用catch处理错误
  2. 避免嵌套Promise
  3. 合理使用Promise.all和Promise.race
  4. 使用async/await简化Promise操作
  5. 注意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,我们可以:

  1. 有效避免回调地狱
  2. 更优雅地处理异步操作
  3. 更好地处理错误
  4. 实现更复杂的异步流程控制

希望本文能帮助你更好地理解和使用Promise!