1.30 - Promise原理、手写Promise
Promise 深度解析与手写实现
从原理到实践,彻底掌握 Promise 的核心机制
目录
- Promise 基础概念
- Promise 核心原理
- 手写 Promise - 基础版
- 手写 Promise - 完整版
- Promise 静态方法实现
- Promise 高级特性
- 常见面试题
- 实战应用场景
一、Promise 基础概念
1.1 什么是 Promise?
Promise 是异步编程的一种解决方案,比传统的回调函数和事件更合理、更强大。它是一个对象,用来表示一个异步操作的最终完成(或失败)及其结果值。
1.2 Promise 的三种状态
// Promise 有且只有三种状态
const PENDING = 'pending'; // 初始状态,既不是成功,也不是失败
const FULFILLED = 'fulfilled'; // 操作成功完成
const REJECTED = 'rejected'; // 操作失败
状态转换规则(核心):
- 状态只能从
pending→fulfilled或pending→rejected - 状态一旦改变,就不会再变,任何时候都可以得到这个结果
fulfilled和rejected状态不可逆,不能相互转换
1.3 Promise 的基本使用
// 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('操作成功'); // 将状态改为 fulfilled
} else {
reject('操作失败'); // 将状态改为 rejected
}
}, 1000);
});
// 使用 Promise
promise
.then(
result => console.log(result), // 成功回调
error => console.log(error) // 失败回调
)
.catch(error => console.log(error)) // 捕获错误
.finally(() => console.log('完成')); // 无论成功失败都执行
二、Promise 核心原理
2.1 Promise 的核心机制
Promise 的实现基于以下几个核心机制:
1. 状态管理
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 当前状态
this.value = undefined; // 成功的值
this.reason = undefined; // 失败的原因
}
}
2. 回调队列
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
}
}
为什么需要回调队列?
- Promise 可能在异步操作完成前就调用
.then() - 此时状态还是
pending,需要先存储回调函数 - 等状态改变后,再依次执行队列中的回调
3. then 方法链式调用
// then 方法必须返回一个新的 Promise
promise
.then(result => result * 2)
.then(result => result + 1)
.then(result => console.log(result));
2.2 Promise 执行流程图
创建 Promise
↓
执行 executor
↓
同步/异步操作
↓
┌─────────┬─────────┐
│ │ │
resolve reject pending
│ │ │
fulfilled rejected 等待中
│ │ │
执行成功 执行失败 存储回调
回调队列 回调队列 到队列
│ │ │
└─────────┴─────────┘
↓
返回新 Promise
↓
链式调用
2.3 关键概念理解
Promise Resolution Procedure(Promise 解决过程)
这是 Promise 最复杂的部分,用于处理 then 返回值:
// 情况 1: 返回普通值
promise.then(() => 123); // 新 Promise 的值是 123
// 情况 2: 返回新的 Promise
promise.then(() => new Promise(resolve => resolve(456))); // 需要等待这个 Promise
// 情况 3: 返回自身
const p = promise.then(() => p); // 需要抛出错误,避免循环引用
// 情况 4: 返回 thenable 对象
promise.then(() => ({
then: (resolve) => resolve(789)
})); // 需要调用其 then 方法
三、手写 Promise - 基础版
3.1 最简单的 Promise 实现
class MyPromise {
constructor(executor) {
// 初始化状态
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// resolve 函数
const resolve = (value) => {
// 只有 pending 状态才能转换
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
}
};
// reject 函数
const reject = (reason) => {
// 只有 pending 状态才能转换
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
}
};
// 立即执行 executor
try {
executor(resolve, reject);
} catch (error) {
// executor 执行出错,直接 reject
reject(error);
}
}
// then 方法
then(onFulfilled, onRejected) {
// 根据状态执行对应回调
if (this.state === 'fulfilled') {
onFulfilled(this.value);
}
if (this.state === 'rejected') {
onRejected(this.reason);
}
}
}
// 测试
const promise = new MyPromise((resolve, reject) => {
resolve('成功');
});
promise.then(
value => console.log(value), // 输出: 成功
reason => console.log(reason)
);
这个版本的问题:
- ❌ 不支持异步操作
- ❌ 不支持链式调用
- ❌ 没有处理回调队列
3.2 支持异步操作
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) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
}
if (this.state === 'rejected') {
onRejected(this.reason);
}
// 新增:处理异步情况
if (this.state === 'pending') {
// 将回调存入队列
this.onFulfilledCallbacks.push(() => {
onFulfilled(this.value);
});
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
});
}
}
}
// 测试异步
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('异步成功');
}, 1000);
});
promise.then(
value => console.log(value), // 1秒后输出: 异步成功
reason => console.log(reason)
);
四、手写 Promise - 完整版
4.1 符合 Promises/A+ 规范的完整实现
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
// 如果 resolve 的是一个 Promise,需要等待其完成
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
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 : reason => { throw reason };
// 返回新的 Promise,实现链式调用
const promise2 = new MyPromise((resolve, reject) => {
// 封装成功回调
const fulfilledMicrotask = () => {
// 使用 queueMicrotask 模拟微任务
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
// Promise 解决过程
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
// 封装失败回调
const rejectedMicrotask = () => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
// 根据状态执行对应逻辑
if (this.state === 'fulfilled') {
fulfilledMicrotask();
} else if (this.state === 'rejected') {
rejectedMicrotask();
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push(fulfilledMicrotask);
this.onRejectedCallbacks.push(rejectedMicrotask);
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
value => MyPromise.resolve(onFinally()).then(() => value),
reason => MyPromise.resolve(onFinally()).then(() => { throw reason })
);
}
}
/**
* Promise 解决过程
* 这是 Promise 最核心的部分
*/
function resolvePromise(promise2, x, resolve, reject) {
// 1. 如果 promise2 和 x 指向同一对象,抛出 TypeError
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 2. 如果 x 是 Promise 实例
if (x instanceof MyPromise) {
x.then(resolve, reject);
return;
}
// 3. 如果 x 是对象或函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let called = false; // 防止多次调用
try {
const then = x.then;
// 如果 then 是函数,认为 x 是 thenable 对象
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 不是函数,直接 resolve
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// 4. x 是普通值,直接 resolve
resolve(x);
}
}
4.2 关键点详解
1. 为什么需要 queueMicrotask?
// 原生 Promise 的回调是微任务
Promise.resolve().then(() => console.log(1));
console.log(2);
// 输出: 2, 1
// 我们的实现也要保证这个顺序
new MyPromise(resolve => resolve()).then(() => console.log(1));
console.log(2);
// 输出: 2, 1
2. resolvePromise 为什么这么复杂?
// 场景 1: 返回普通值
promise.then(() => 123);
// 场景 2: 返回 Promise
promise.then(() => new Promise(resolve => resolve(456)));
// 场景 3: 返回 thenable 对象
promise.then(() => ({
then: (resolve) => setTimeout(() => resolve(789), 1000)
}));
// 场景 4: 循环引用
const p = promise.then(() => p); // 必须抛出错误
// 场景 5: 嵌套 Promise
promise.then(() =>
new Promise(resolve =>
resolve(new Promise(r => r(999)))
)
);
3. called 标志的作用
// 防止 thenable 对象多次调用 resolve/reject
const thenable = {
then: (resolve, reject) => {
resolve(1);
resolve(2); // 应该被忽略
reject(3); // 应该被忽略
}
};
MyPromise.resolve(thenable).then(value => {
console.log(value); // 只输出 1
});
五、Promise 静态方法实现
5.1 Promise.resolve
MyPromise.resolve = function(value) {
// 如果是 Promise 实例,直接返回
if (value instanceof MyPromise) {
return value;
}
// 如果是 thenable 对象
if (value !== null && typeof value === 'object' && typeof value.then === 'function') {
return new MyPromise((resolve, reject) => {
value.then(resolve, reject);
});
}
// 普通值,返回成功的 Promise
return new MyPromise(resolve => resolve(value));
};
// 测试
MyPromise.resolve(123).then(value => console.log(value)); // 123
MyPromise.resolve(MyPromise.resolve(456)).then(value => console.log(value)); // 456
5.2 Promise.reject
MyPromise.reject = function(reason) {
// 无论传入什么,都返回失败的 Promise
return new MyPromise((resolve, reject) => reject(reason));
};
// 测试
MyPromise.reject('error').catch(reason => console.log(reason)); // error
5.3 Promise.all
MyPromise.all = function(promises) {
return new MyPromise((resolve, reject) => {
// 参数校验
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let completedCount = 0;
const length = promises.length;
// 空数组直接返回
if (length === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
// 将非 Promise 值转为 Promise
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completedCount++;
// 所有 Promise 都完成
if (completedCount === length) {
resolve(results);
}
},
reason => {
// 任何一个失败,立即 reject
reject(reason);
}
);
});
});
};
// 测试
MyPromise.all([
MyPromise.resolve(1),
MyPromise.resolve(2),
MyPromise.resolve(3)
]).then(values => console.log(values)); // [1, 2, 3]
MyPromise.all([
MyPromise.resolve(1),
MyPromise.reject('error'),
MyPromise.resolve(3)
]).catch(reason => console.log(reason)); // error
5.4 Promise.race
MyPromise.race = function(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
// 空数组,永远 pending
if (promises.length === 0) {
return;
}
promises.forEach(promise => {
// 第一个完成的 Promise 决定结果
MyPromise.resolve(promise).then(resolve, reject);
});
});
};
// 测试
MyPromise.race([
new MyPromise(resolve => setTimeout(() => resolve(1), 1000)),
new MyPromise(resolve => setTimeout(() => resolve(2), 500)),
new MyPromise(resolve => setTimeout(() => resolve(3), 800))
]).then(value => console.log(value)); // 500ms 后输出 2
5.5 Promise.allSettled
MyPromise.allSettled = function(promises) {
return new MyPromise((resolve) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let completedCount = 0;
const length = promises.length;
if (length === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = { status: 'fulfilled', value };
completedCount++;
if (completedCount === length) {
resolve(results);
}
},
reason => {
results[index] = { status: 'rejected', reason };
completedCount++;
if (completedCount === length) {
resolve(results);
}
}
);
});
});
};
// 测试
MyPromise.allSettled([
MyPromise.resolve(1),
MyPromise.reject('error'),
MyPromise.resolve(3)
]).then(results => console.log(results));
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 3 }
// ]
5.6 Promise.any
MyPromise.any = function(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const errors = [];
let rejectedCount = 0;
const length = promises.length;
if (length === 0) {
return reject(new AggregateError([], 'All promises were rejected'));
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
// 任何一个成功,立即 resolve
resolve(value);
},
reason => {
errors[index] = reason;
rejectedCount++;
// 所有都失败,才 reject
if (rejectedCount === length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
};
// 测试
MyPromise.any([
MyPromise.reject('error1'),
MyPromise.resolve(2),
MyPromise.reject('error3')
]).then(value => console.log(value)); // 2
MyPromise.any([
MyPromise.reject('error1'),
MyPromise.reject('error2')
]).catch(error => console.log(error)); // AggregateError
六、Promise 高级特性
6.1 Promise 链式调用的值传递
// 值穿透
Promise.resolve(1)
.then() // 没有处理函数
.then() // 没有处理函数
.then(value => {
console.log(value); // 1
});
// 实现原理
then(onFulfilled, onRejected) {
// 如果不是函数,提供默认函数
onFulfilled = typeof onFulfilled === 'function'
? onFulfilled
: value => value; // 值穿透
onRejected = typeof onRejected === 'function'
? onRejected
: reason => { throw reason }; // 错误穿透
}
6.2 错误处理机制
// 错误会一直传递,直到被 catch
Promise.resolve()
.then(() => {
throw new Error('错误1');
})
.then(() => {
console.log('不会执行');
})
.then(() => {
console.log('不会执行');
})
.catch(error => {
console.log(error.message); // 错误1
return 'recovered';
})
.then(value => {
console.log(value); // recovered
});
6.3 Promise 的中断
// Promise 没有官方的中断方法,但可以通过返回一个永远 pending 的 Promise 来"中断"
function interruptPromise() {
return new Promise(() => {}); // 永远不 resolve 也不 reject
}
Promise.resolve()
.then(() => {
console.log('step 1');
return interruptPromise(); // 后续不会执行
})
.then(() => {
console.log('不会执行');
});
6.4 Promise 的重试机制
/**
* Promise 重试函数
* @param {Function} fn - 需要重试的函数
* @param {Number} times - 重试次数
* @param {Number} delay - 重试延迟
*/
function retry(fn, times = 3, delay = 1000) {
return new Promise((resolve, reject) => {
function attempt(remainingTimes) {
fn()
.then(resolve)
.catch(error => {
if (remainingTimes === 0) {
reject(error);
} else {
console.log(`失败,${delay}ms 后重试,剩余次数: ${remainingTimes}`);
setTimeout(() => {
attempt(remainingTimes - 1);
}, delay);
}
});
}
attempt(times);
});
}
// 使用示例
let count = 0;
const unstableApi = () => {
return new Promise((resolve, reject) => {
count++;
if (count < 3) {
reject(`失败 ${count} 次`);
} else {
resolve('成功');
}
});
};
retry(unstableApi, 5, 500)
.then(result => console.log(result))
.catch(error => console.log(error));
6.5 Promise 并发控制
/**
* 并发控制函数
* @param {Array} tasks - 任务数组
* @param {Number} limit - 并发限制
*/
function concurrentControl(tasks, limit = 2) {
return new Promise((resolve) => {
const results = [];
let runningCount = 0;
let completedCount = 0;
let index = 0;
function run() {
while (runningCount < limit && index < tasks.length) {
const currentIndex = index;
const task = tasks[index++];
runningCount++;
task()
.then(result => {
results[currentIndex] = result;
})
.catch(error => {
results[currentIndex] = error;
})
.finally(() => {
runningCount--;
completedCount++;
if (completedCount === tasks.length) {
resolve(results);
} else {
run();
}
});
}
}
run();
});
}
// 使用示例
const tasks = [
() => new Promise(resolve => setTimeout(() => resolve('任务1'), 1000)),
() => new Promise(resolve => setTimeout(() => resolve('任务2'), 500)),
() => new Promise(resolve => setTimeout(() => resolve('任务3'), 800)),
() => new Promise(resolve => setTimeout(() => resolve('任务4'), 300)),
() => new Promise(resolve => setTimeout(() => resolve('任务5'), 600))
];
concurrentControl(tasks, 2).then(results => {
console.log(results);
});
七、常见面试题
7.1 Promise 执行顺序题
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('3');
});
}, 0);
new Promise((resolve) => {
console.log('4');
resolve();
}).then(() => {
console.log('5');
}).then(() => {
console.log('6');
});
console.log('7');
// 输出顺序: 1, 4, 7, 5, 6, 2, 3
/**
* 解析:
* 1. 同步代码: 1, 4, 7
* 2. 微任务队列: 5 -> 6
* 3. 宏任务队列: 2 -> 微任务 3
*/
7.2 Promise 红绿灯问题
// 红灯3秒亮一次,绿灯2秒亮一次,黄灯1秒亮一次
// 实现一个函数让三个灯循环亮起
function red() {
console.log('红灯');
}
function green() {
console.log('绿灯');
}
function yellow() {
console.log('黄灯');
}
function light(callback, delay) {
return new Promise((resolve) => {
setTimeout(() => {
callback();
resolve();
}, delay);
});
}
function step() {
Promise.resolve()
.then(() => light(red, 3000))
.then(() => light(green, 2000))
.then(() => light(yellow, 1000))
.then(() => step()); // 循环
}
step();
7.3 实现 Promise.map
/**
* Promise.map
* 类似 Promise.all,但可以控制并发数
*/
Promise.map = function(promises, concurrency = Infinity) {
return new Promise((resolve, reject) => {
const results = [];
const total = promises.length;
let completed = 0;
let running = 0;
let index = 0;
function run() {
if (completed === total) {
return resolve(results);
}
while (running < concurrency && index < total) {
const currentIndex = index;
running++;
index++;
Promise.resolve(promises[currentIndex])
.then(value => {
results[currentIndex] = value;
completed++;
running--;
run();
})
.catch(reject);
}
}
run();
});
};
// 测试
const tasks = [
() => new Promise(resolve => setTimeout(() => resolve(1), 1000)),
() => new Promise(resolve => setTimeout(() => resolve(2), 500)),
() => new Promise(resolve => setTimeout(() => resolve(3), 800))
];
Promise.map(tasks.map(task => task()), 2).then(console.log);
7.4 实现 promisify
/**
* 将 callback 风格的函数转为 Promise 风格
*/
function promisify(fn) {
return function(...args) {
return new Promise((resolve, reject) => {
fn(...args, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
}
// 使用示例
const fs = require('fs');
const readFilePromise = promisify(fs.readFile);
readFilePromise('file.txt', 'utf8')
.then(content => console.log(content))
.catch(error => console.error(error));
7.5 实现 Promise 串行执行
/**
* 串行执行 Promise
*/
function sequencePromises(promises) {
return promises.reduce((prev, current) => {
return prev.then(current);
}, Promise.resolve());
}
// 使用示例
const tasks = [
() => new Promise(resolve => {
setTimeout(() => {
console.log('任务1');
resolve();
}, 1000);
}),
() => new Promise(resolve => {
setTimeout(() => {
console.log('任务2');
resolve();
}, 500);
}),
() => new Promise(resolve => {
setTimeout(() => {
console.log('任务3');
resolve();
}, 800);
})
];
sequencePromises(tasks);
// 输出: 任务1 (1秒后) -> 任务2 (0.5秒后) -> 任务3 (0.8秒后)
八、实战应用场景
8.1 请求超时控制
function timeoutPromise(promise, timeout = 5000) {
return Promise.race([
promise,
new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`请求超时,超过 ${timeout}ms`));
}, timeout);
})
]);
}
// 使用示例
const fetchData = fetch('https://api.example.com/data');
timeoutPromise(fetchData, 3000)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
8.2 图片预加载
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`图片加载失败: ${url}`));
img.src = url;
});
}
function preloadImages(urls) {
const promises = urls.map(url => loadImage(url));
return Promise.all(promises);
}
// 使用示例
const imageUrls = [
'image1.jpg',
'image2.jpg',
'image3.jpg'
];
preloadImages(imageUrls)
.then(images => {
console.log('所有图片加载完成', images);
})
.catch(error => {
console.error('图片加载失败', error);
});
8.3 缓存 Promise 结果
function cachePromise(fn) {
let cache = null;
let cacheTime = 0;
const CACHE_DURATION = 60000; // 缓存1分钟
return function(...args) {
const now = Date.now();
// 缓存未过期,直接返回
if (cache && now - cacheTime < CACHE_DURATION) {
return Promise.resolve(cache);
}
// 执行函数并缓存结果
return fn(...args).then(result => {
cache = result;
cacheTime = now;
return result;
});
};
}
// 使用示例
const fetchUserData = cachePromise((userId) => {
return fetch(`https://api.example.com/users/${userId}`)
.then(response => response.json());
});
// 第一次调用,发起请求
fetchUserData(123).then(data => console.log(data));
// 1分钟内再次调用,直接返回缓存
fetchUserData(123).then(data => console.log(data));
8.4 Promise 请求去重
/**
* 相同的请求在 pending 期间,只发起一次
*/
function dedupeFetch() {
const pendingPromises = new Map();
return function(url, options) {
const key = `${url}_${JSON.stringify(options)}`;
// 如果已有相同请求在 pending,返回该 Promise
if (pendingPromises.has(key)) {
return pendingPromises.get(key);
}
// 创建新请求
const promise = fetch(url, options)
.then(response => response.json())
.finally(() => {
// 请求完成后删除
pendingPromises.delete(key);
});
pendingPromises.set(key, promise);
return promise;
};
}
const fetchData = dedupeFetch();
// 同时发起三个相同请求,实际只会发送一次
fetchData('/api/data', { method: 'GET' }).then(console.log);
fetchData('/api/data', { method: 'GET' }).then(console.log);
fetchData('/api/data', { method: 'GET' }).then(console.log);
九、总结与面试要点
9.1 核心知识点
-
Promise 三种状态
- pending, fulfilled, rejected
- 状态只能单向转换,不可逆
-
Promise 的关键机制
- 回调队列(处理异步)
- 链式调用(then 返回新 Promise)
- 值传递(resolvePromise)
-
微任务与宏任务
- Promise.then 是微任务
- setTimeout 是宏任务
- 微任务优先于宏任务执行
-
错误处理
- catch 可以捕获 Promise 链中的所有错误
- finally 无论成功失败都会执行
- 未捕获的 Promise 错误会导致 unhandledRejection
9.2 面试高频问题
Q1: Promise 解决了什么问题?
- 解决回调地狱(callback hell)
- 统一异步操作的接口
- 更好的错误处理机制
- 支持链式调用
Q2: Promise 和 async/await 的区别?
- async/await 是 Promise 的语法糖
- async/await 使异步代码看起来像同步代码
- 错误处理: Promise 用 catch,async/await 用 try/catch
Q3: Promise.all 和 Promise.allSettled 的区别?
- Promise.all: 任何一个失败就立即 reject
- Promise.allSettled: 等待所有 Promise 完成,无论成功失败
Q4: 如何取消一个 Promise?
- Promise 本身不支持取消
- 可以使用 AbortController(Fetch API)
- 或返回一个永远 pending 的 Promise 来”中断”链条
9.3 手写能力检查清单
✅ 能实现基础的 Promise(状态管理、resolve/reject) ✅ 能实现 then 方法的链式调用 ✅ 能实现 resolvePromise(处理各种返回值) ✅ 能实现 Promise.all / race / allSettled / any ✅ 能实现 Promise.resolve / reject ✅ 理解微任务与宏任务的执行顺序 ✅ 能解决实际问题(并发控制、重试、超时等)
十、完整可测试代码
/**
* 完整的 MyPromise 实现
* 符合 Promises/A+ 规范
*/
class MyPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
this.state = MyPromise.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
if (this.state === MyPromise.PENDING) {
this.state = MyPromise.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === MyPromise.PENDING) {
this.state = MyPromise.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 : reason => { throw reason };
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
const rejectedMicrotask = () => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
if (this.state === MyPromise.FULFILLED) {
fulfilledMicrotask();
} else if (this.state === MyPromise.REJECTED) {
rejectedMicrotask();
} else {
this.onFulfilledCallbacks.push(fulfilledMicrotask);
this.onRejectedCallbacks.push(rejectedMicrotask);
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
value => MyPromise.resolve(onFinally()).then(() => value),
reason => MyPromise.resolve(onFinally()).then(() => { throw reason })
);
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
static all(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let count = 0;
if (promises.length === 0) return resolve(results);
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
count++;
if (count === promises.length) resolve(results);
},
reject
);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
static allSettled(promises) {
return new MyPromise((resolve) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const results = [];
let count = 0;
if (promises.length === 0) return resolve(results);
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = { status: 'fulfilled', value };
count++;
if (count === promises.length) resolve(results);
},
reason => {
results[index] = { status: 'rejected', reason };
count++;
if (count === promises.length) resolve(results);
}
);
});
});
}
static any(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument must be an array'));
}
const errors = [];
let count = 0;
if (promises.length === 0) {
return reject(new AggregateError([], 'All promises were rejected'));
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
resolve,
reason => {
errors[index] = reason;
count++;
if (count === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
return;
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let called = false;
try {
const then = x.then;
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 {
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x);
}
}
// ==================== 测试用例 ====================
console.log('=== 测试1: 基本功能 ===');
new MyPromise((resolve) => {
setTimeout(() => resolve('成功'), 100);
}).then(value => console.log('结果:', value));
console.log('\n=== 测试2: 链式调用 ===');
MyPromise.resolve(1)
.then(value => value + 1)
.then(value => value * 2)
.then(value => console.log('链式结果:', value));
console.log('\n=== 测试3: 错误处理 ===');
MyPromise.reject('错误')
.catch(error => console.log('捕获到:', error));
console.log('\n=== 测试4: Promise.all ===');
MyPromise.all([
MyPromise.resolve(1),
MyPromise.resolve(2),
MyPromise.resolve(3)
]).then(values => console.log('all 结果:', values));
console.log('\n=== 测试5: Promise.race ===');
MyPromise.race([
new MyPromise(resolve => setTimeout(() => resolve('慢'), 1000)),
new MyPromise(resolve => setTimeout(() => resolve('快'), 100))
]).then(value => console.log('race 结果:', value));
🎯 学习建议:
- 理解原理: 先理解 Promise 的状态机制和执行流程
- 动手实现: 从简单版本开始,逐步完善功能
- 调试测试: 运行代码,观察输出,理解每一步
- 应用实践: 在实际项目中使用 Promise 解决问题
- 面试准备: 能够清晰解释原理,流畅手写代码
💡 记住这句话:
Promise 的核心是状态管理 + 回调队列 + 链式调用,掌握这三点就掌握了 Promise 的精髓!
祝你面试顺利,工作游刃有余!🚀