可能是目前最易理解的手写Promise:从零实现异步核心
2025.09.19 12:47浏览量:0简介:本文通过分步骤拆解Promise核心机制,结合代码示例与可视化流程图,系统讲解如何从零实现一个符合A+规范的Promise。内容覆盖状态管理、链式调用、异常处理等关键模块,并附完整实现代码与测试用例。
一、Promise核心机制解析
Promise作为现代JavaScript异步编程的基石,其设计本质是解决”回调地狱”与”信任问题”。标准Promise对象包含三个关键要素:
- 状态机:pending → fulfilled/rejected的单向转换
- 微任务队列:通过
queueMicrotask
实现的异步调度 - 链式调用:基于
.then()
方法的值透传与错误冒泡
1.1 状态管理实现
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // 成功值
this.reason = undefined; // 失败原因
this.callbacks = []; // 存储then回调
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 执行所有成功回调
this.callbacks.forEach(cb => cb.onResolve(value));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 执行所有失败回调
this.callbacks.forEach(cb => cb.onReject(reason));
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
状态转换遵循严格规则:一旦状态从pending改变,将不可逆。这种设计保证了异步操作的确定性。
1.2 异步调度原理
标准Promise使用微任务(Microtask)而非宏任务(Macrotask)实现异步,确保在当前事件循环结束前执行:
// 简化版微任务调度
const scheduleMicrotask = (callback) => {
queueMicrotask(callback); // 现代浏览器原生支持
// 或使用MutationObserver兼容旧环境
};
这种设计使Promise的.then()回调优先级高于setTimeout等宏任务,形成明确的执行顺序。
二、链式调用实现
链式调用的核心在于.then()
方法返回新Promise的特性,结合值透传与错误冒泡机制:
2.1 基本链式结构
MyPromise.prototype.then = function(onResolve, onReject) {
// 参数可选处理
onResolve = typeof onResolve === 'function' ? onResolve : v => v;
onReject = typeof onReject === 'function' ? onReject : r => { throw r; };
const promise2 = new MyPromise((resolve, reject) => {
const handleFulfilled = (value) => {
try {
const x = onResolve(value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
};
const handleRejected = (reason) => {
try {
const x = onReject(reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
};
if (this.state === 'fulfilled') {
scheduleMicrotask(() => handleFulfilled(this.value));
} else if (this.state === 'rejected') {
scheduleMicrotask(() => handleRejected(this.reason));
} else {
this.callbacks.push({
onResolve: handleFulfilled,
onReject: handleRejected
});
}
});
return promise2;
};
2.2 异步值解析协议
resolvePromise
函数处理thenable对象的解析,遵循A+规范:
function resolvePromise(promise2, x, resolve, reject) {
// 防止循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
let called = false;
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
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 (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
该实现确保当thenable对象(如另一个Promise)被返回时,能正确解析其最终状态。
三、静态方法实现
标准Promise包含的静态方法可通过类似机制实现:
3.1 Promise.resolve/reject
MyPromise.resolve = function(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
};
MyPromise.reject = function(reason) {
return new MyPromise((_, reject) => reject(reason));
};
3.2 Promise.all实现
MyPromise.all = function(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let completed = 0;
if (promises.length === 0) {
resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completed++;
if (completed === promises.length) {
resolve(results);
}
},
reason => reject(reason)
);
});
});
};
四、实际应用建议
- 调试技巧:在.then()中始终返回明确值,避免隐式返回值
```javascript
// 不推荐
promise.then(value => {
doSomething(value); // 无返回值,下一个then将收到undefined
});
// 推荐
promise.then(value => {
doSomething(value);
return processedValue;
});
2. **错误处理**:使用catch()进行集中错误处理
```javascript
// 优于多个.then(null, errHandler)
getData()
.then(process)
.then(transform)
.catch(handleError);
- 性能优化:避免在循环中创建大量Promise,考虑批量处理
```javascript
// 低效实现
const promises = [];
for (let i = 0; i < 1000; i++) {
promises.push(fetchData(i)); // 同步创建1000个Promise
}
// 优化方案
async function batchFetch(start, end) {
const results = [];
for (let i = start; i < end; i++) {
results.push(await fetchData(i)); // 顺序执行,控制并发
}
return results;
}
# 五、完整实现代码
```javascript
// 完整实现见上文各模块组合
// 测试用例
const test = new MyPromise(resolve => {
setTimeout(() => resolve(1), 1000);
});
test
.then(v => {
console.log(v); // 1
return v * 2;
})
.then(v => {
console.log(v); // 2
throw new Error('error');
})
.catch(e => {
console.error(e.message); // 'error'
return 3;
})
.then(v => {
console.log(v); // 3
});
通过这种模块化实现方式,开发者可以清晰理解Promise每个环节的工作原理。建议在实际项目中,先基于这种简化版实现理解核心机制,再逐步使用原生Promise或成熟的库(如bluebird)以获得更好的性能和兼容性。
发表评论
登录后可评论,请前往 登录 或 注册