接着上一篇文章继续写:
本篇内容,让上篇的 MiniPromise 支持链式调用,并且符合 Promise/A+ 规范。这个规范有 872 个测试用例,实现目标是一个都不挂。
上篇的 MiniPromise 能跑异步、有 catch/finally 的 mini Promise,但它丢了一个 Promise 最核心的能力:链式调用。
下面的就是链式调用示例:
js
fetch('/api/user')
.then((res) => res.json()) // 第一个 then 返回新 Promise
.then((user) => fetch(`/api/orders/${user.id}`)) // 第二个 then
.then((res) => res.json()) // 第三个 then
.catch(console.error);
每一个 .then() 都返回一个全新的 Promise ,后一个 .then() 实际上是挂在这个新 Promise 上的。这就是链的精髓。
让上篇的 MiniPromise 支持链式调用,并且符合 Promise/A+ 规范。这个规范有 872 个测试用例,实现目标是一个都不挂。
then 必须返回一个新 Promise
1.1 什么是「新 Promise」
看这个代码:
js
const p1 = Promise.resolve(1);
const p2 = p1.then((v) => v + 1);
console.log(p1 === p2); // false 不是同一个对象!
.then() 不会修改原来的 Promise,而是创建一个新的 Promise。新 Promise 的状态由回调的返回值决定。
1.2 动手实现
js
then(onFulfilled, onRejected) {
// 关键:then 返回一个新的 Promise 实例
const promise2 = new MiniPromise((resolve, reject) => {
if (this.state === FULFILLED) {
// 执行成功回调,用返回值 resolve promise2
const x = onFulfilled(this.value);
resolve(x);
}
if (this.state === REJECTED) {
const x = onRejected(this.reason);
resolve(x); // 注意:错误被处理了,promise2 是 fulfilled
}
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(() => {
const x = onFulfilled(this.value);
resolve(x);
});
this.onRejectedCallbacks.push(() => {
const x = onRejected(this.reason);
resolve(x);
});
}
});
return promise2;
}
验证链式调用
js
const p = new MiniPromise((resolve) => resolve(1));
p.then((v) => {
console.log('第一个 then:', v); // 1
return v + 1;
})
.then((v) => {
console.log('第二个 then:', v); // 2
return v + 1;
})
.then((v) => {
console.log('第三个 then:', v); // 3
});
能跑了, 但还有两个问题需要解决。
不传回调也能传递值--值穿透
2.1 原生 Promise 的神奇行为
js
Promise.resolve(1)
.then() // 没传任何回调!
.then() // 还是没传
.then((v) => console.log(v)); // 输出 1
这个特性叫值穿透 。如果一个 .then() 没传成功回调,值就自动传给下一个 .then()。错误也一样:如果没传失败回调,错误会沿着链一直穿透,直到遇到 .catch()。
js
Promise.reject('出错了')
.then((v) => v) // 有成功回调,但错误不会进这里
.then((v) => v) // 同上
.catch((e) => console.log(e)); // '出错了'
2.2 实现值穿透
原理很简单:如果用户没传回调,我们就给一个默认回调:
- 成功默认回调:
(v) => v------ 把值直接返回 - 失败默认回调:
(e) => { throw e }------ 把错误重新抛出去
js
then(onFulfilled, onRejected) {
// 值穿透处理
onFulfilled = typeof onFulfilled === 'function'
? onFulfilled
: (value) => value; // 默认:原样传递
onRejected = typeof onRejected === 'function'
? onRejected
: (err) => { throw err; }; // 默认:重新抛出错误
const promise2 = new MiniPromise((resolve, reject) => {
// 同时用 try/catch 包裹,防止回调抛异常
if (this.state === FULFILLED) {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
}
if (this.state === REJECTED) {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (e) {
reject(e);
}
}
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
});
this.onRejectedCallbacks.push(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (e) {
reject(e);
}
});
}
});
return promise2;
}
验证
js
const p = new MiniPromise((resolve) => resolve('hello'));
p.then() // 没传回调
.then() // 没传回调
.then((v) => console.log(v)); // 'hello' ✅
const p2 = new MiniPromise((resolve, reject) => reject('错误'));
p2.then((v) => v) // 只传了成功回调
.then((v) => v) // 只传了成功回调
.catch((e) => console.log(e)); // '错误' ✅ 穿透成功!
验证异常捕获
js
new MiniPromise((resolve) => resolve('ok'))
.then((v) => {
throw new Error('中间炸了');
})
.then((v) => console.log('不会执行'))
.catch((e) => console.log('捕获:', e.message)); // 捕获: 中间炸了
Promise 解析过程(resolvePromise)
3.1 问题出在哪?
先看这段代码:
js
Promise.resolve(1)
.then((v) => {
// 回调返回了一个新的 Promise!
return new Promise((resolve) => {
setTimeout(() => resolve(v + 1), 1000);
});
})
.then((v) => console.log(v));
这段代码的行为是什么?
- 1 秒后打印
2 - 第二个
.then()在等待第一个.then()回调里返回的那个 Promise
但现在 MiniPromise 代码现在的逻辑如下:
js
const x = onFulfilled(this.value); // x 是一个 Promise 对象
resolve(x); // 直接把 Promise 对象当成值传下去了 不对!
这样第二个 .then() 会立即拿到一个 Promise 对象,而不是等它 resolve 后的 2。
3.2 规范怎么说的?
Promise/A+ 规范的第 2.3 节定义了 Promise Resolution Procedure,专门处理这个问题。核心思想是:
如果
x是一个 thenable(有.then方法的对象或函数),就用它的.then方法来决定 promise2 的状态。
通俗一点来说就是:如果回调返回了一个 Promise,你得等这个 Promise 完成,然后把它的结果传递给下一个 then。
这个逻辑需要单独抽一个函数来处理,规范里叫 [[Resolve]](promise, x):
js
/**
* Promise 解析过程 ------ 核心中的核心
*
* @param {Promise} promise2 - then 返回的那个新 Promise
* @param {*} x - 回调函数的返回值
* @param {Function} resolve - promise2 的 resolve
* @param {Function} reject - promise2 的 reject
*/
function resolvePromise(promise2, x, resolve, reject) {
// 【规则 2.3.1】如果 promise2 和 x 是同一个东西,死循环了
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
// 【防抖】确保 resolve/reject 只被调用一次
let called = false;
// 【规则 2.3.3】如果 x 是对象或函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 拿 x.then,可能抛异常(比如访问受限属性)
const then = x.then;
// 【规则 2.3.3.3】如果 then 是函数,认为 x 是一个 thenable
if (typeof then === 'function') {
// 用 x 作为 this 调用 then 方法
then.call(
x,
// 成功回调:resolvePromise
(y) => {
if (called) return;
called = true;
// 🌀 关键:递归解析!因为 y 可能还是一个 Promise
resolvePromise(promise2, y, resolve, reject);
},
// 失败回调:rejectPromise
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
// 【规则 2.3.3.4】then 不是函数,x 是普通对象,直接 resolve
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// 【规则 2.3.4】x 不是对象也不是函数(数字、字符串、null 等),直接 resolve
resolve(x);
}
}
3.3 尝试拆解一下这个函数
不要被代码量吓到,只看重点,拆开来看就是以下四个场景:
场景 1:x 是普通值(数字、字符串、null、undefined)
ini
x = 42 → 直接 resolve(42),简单。
场景 2:x 是普通对象(没有 .then 方法)
css
x = { name: '熊' } → 直接 resolve({ name: '熊' })
场景 3:x 是 Promise(有 .then 方法)
scss
x = new Promise(resolve => setTimeout(() => resolve(42), 1000))
→ 调用 x.then(
y => resolvePromise(promise2, y, resolve, reject), // y 可能是 42
r => reject(r)
)
→ 1 秒后,y = 42,递归调用 resolvePromise(promise2, 42, resolve, reject)
→ 42 是普通值 → resolve(42) ✅
场景 4:x === promise2(循环引用)
scss
p.then(() => p) → 直接 reject(TypeError)
resolvePromise 的递归过程
假设有这样的代码:
js
new MiniPromise((resolve) => resolve(1))
.then((v) => new MiniPromise((resolve) => resolve(v + 1)))
.then((v) => console.log(v));
resolvePromise 的执行流程:
ini
第一次调用:
promise2 = then1返回的Promise
x = MiniPromise(resolve => resolve(2))
x 是对象 ✓
x.then 是函数 ✓
→ 调用 x.then(resolvePromise, reject)
异步:x 的 resolve(2) 触发
→ resolvePromise 被调用,参数 y = 2
第二次调用(递归):
promise2 = 同上
x = 2
x 是数字,不是对象 → resolve(2)
→ promise2 变成 fulfilled,值为 2
→ 第二个 .then(v => console.log(v)) 打印 2
3.4 把 resolvePromise 接到 then 里
js
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
onRejected = typeof onRejected === 'function' ? onRejected : (e) => { throw e; };
const promise2 = new MiniPromise((resolve, reject) => {
if (this.state === FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 🆕 用 resolvePromise 代替 resolve(x)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
用 setTimeout(..., 0) 把回调包装成了异步, 是为了模拟 Promise 回调的微任务行为(真正的 Promise 用微任务,MiniPromise 暂时用宏任务近似)。
验证then 里返回 Promise
js
new MiniPromise((resolve) => resolve(1))
.then((v) => {
console.log('then1:', v);
return new MiniPromise((resolve) => {
setTimeout(() => resolve(v + 1), 1000);
});
})
.then((v) => {
console.log('then2:', v); // 1 秒后打印 2 ✅
});
验证循环引用检测
js
const p = new MiniPromise((resolve) => resolve());
const p2 = p.then(() => p2); // 自己返回自己
p2.catch((e) => console.log(e.message));
// Chaining cycle detected ✅
🧪 高级测试:多层嵌套 Promise
js
new MiniPromise((resolve) => resolve(1))
.then((v) => {
return new MiniPromise((resolve) => {
resolve(
new MiniPromise((resolve) => {
resolve(
new MiniPromise((resolve) => {
resolve(v + 10);
})
);
})
);
});
})
.then((v) => console.log(v)); // 11 ✅ 递归展开了 3 层!
用 promises-aplus-tests 验证
Promise/A+ 规范有一个官方的测试套件 promises-aplus-tests,包含 872 个测试用例。我们来跑一下。
4.1 写出完整代码
js
// my-promise.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
let called = false;
if (x !== null && (typeof x === 'object' || 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);
}
}
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 (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
onRejected = typeof onRejected === 'function' ? onRejected : (e) => { throw e; };
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledTask = () => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
const rejectedTask = () => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === FULFILLED) {
fulfilledTask();
} else if (this.state === REJECTED) {
rejectedTask();
} else if (this.state === PENDING) {
this.onFulfilledCallbacks.push(fulfilledTask);
this.onRejectedCallbacks.push(rejectedTask);
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
关于 catch 的三个重要认知
第一个:catch 就是 then(null, callback) 的语法糖。 但社区强烈推荐用 .catch() 而不是 .then(null, fn),原因很简单------.then(successFn, errorFn) 里的 errorFn 只能捕获 then 之前的错误,捕获不到 successFn 里的错误。
js
// 不好的写法:then 的第二个参数抓不到 success 回调里的错
promise.then(
(data) => {
throw new Error('处理数据时出错');
},
(err) => {
// 抓不到上面那个错误!因为它只监听 promise 的 reject
console.log('抓不到');
}
);
// 好写法:catch 在后面,前面 then 里的错也能收
promise
.then((data) => {
throw new Error('处理数据时出错');
})
.catch((err) => {
console.log('抓到了!', err.message);
});
通俗一点就是:then 的成功回调和失败回调各管各的,但 .catch() 像一张大网,前面所有链上的错误都能兜住。
第二个:catch 之后状态变成 fulfilled,链可以继续走。 这叫「错误恢复」。
js
Promise.reject('出错了')
.catch((e) => {
console.log('处理错误:', e);
return '已恢复'; // ← catch 返回了值,Promise 状态变 fulfilled
})
.then((v) => {
console.log('继续:', v); // 继续: 已恢复 ✅
});
但 catch 里如果又 throw 了,那就是新的 rejection,需要后面再有 catch 接着。
js
someAsyncThing()
.then(fn)
.catch((e) => {
console.log('第一个错误:', e);
y + 2; // y 没定义,又出错了!
})
.catch((e) => {
console.log('第二个错误:', e); // 这个 catch 抓到了上面 catch 里的错
});
第三个:没有 catch 的 Promise,错误不会被外部 try/catch 捕获。 Promise 会「吃掉」内部错误------代码不会崩,但错误消失了。Node.js 有 unhandledRejection 事件专门抓这种静默失败。建议生产环境全局注册它。
js
// Node.js
process.on('unhandledRejection', (reason, promise) => {
console.error('未捕获的 Promise 错误:', reason);
// 上报到错误监控平台
});
// 浏览器
window.addEventListener('unhandledrejection', (event) => {
console.error('未捕获的 Promise 错误:', event.reason);
});
第四步:用 promises-aplus-tests 验证
Promise/A+ 规范有一个官方的测试套件 promises-aplus-tests,包含 872 个测试用例。我们来跑一下。
4.1 写出完整代码
js
// my-promise.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
let called = false;
if (x !== null && (typeof x === 'object' || 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);
}
}
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 (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
onRejected = typeof onRejected === 'function' ? onRejected : (e) => { throw e; };
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledTask = () => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
const rejectedTask = () => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === FULFILLED) {
fulfilledTask();
} else if (this.state === REJECTED) {
rejectedTask();
} else if (this.state === PENDING) {
this.onFulfilledCallbacks.push(fulfilledTask);
this.onRejectedCallbacks.push(rejectedTask);
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
module.exports = MyPromise;
4.2 跑测试
上面输出的是完整版的代码,跑测试的话需要添加导出deferred测试适配器
javascript
// 上方的 module.exports = MyPromise 改为:
module.exports = {
deferred() {
let resolve, reject;
const promise = new MyPromise((res, rej) => {
resolve = res;
reject = rej;
});
return {
promise,
resolve,
reject
};
}
};
bash
npm install promises-aplus-tests --save-dev
npx promises-aplus-tests my-promise.js
!image-20260627132905402(/Users/jindacheng/Library/Application Support/typora-user-images/image-20260627132905402.png)
如果看到 872 passing,那么就说明通过了 Promise/A+ 规范的全部测试!
实践
练习 1:实现 delay 函数(链式调用版)
js
function delay(ms, value) {
return new MyPromise((resolve) => {
setTimeout(() => resolve(value), ms);
});
}
delay(500, '第一步')
.then((v) => {
console.log(v);
return delay(500, '第二步');
})
.then((v) => {
console.log(v);
return delay(500, '第三步');
})
.then(console.log);
// 每 500ms 依次打印:第一步 → 第二步 → 第三步
练习 2:实现一个请求重试函数
js
/**
* 请求重试
* @param {Function} fn - 返回 Promise 的请求函数
* @param {number} times - 最大重试次数
* @param {number} delayMs - 重试间隔
*/
function retry(fn, times = 3, delayMs = 1000) {
return new MyPromise((resolve, reject) => {
function attempt(n) {
fn()
.then(resolve)
.catch((err) => {
if (n <= 1) {
return reject(err);
}
console.log(`第 ${times - n + 1} 次失败,${delayMs}ms 后重试...`);
delay(delayMs).then(() => attempt(n - 1));
});
}
attempt(times);
});
}
// 模拟一个不稳定请求
let count = 0;
function unstableRequest() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
count++;
if (count < 3) {
reject(new Error('网络错误'));
} else {
resolve('成功!');
}
}, 500);
});
}
retry(unstableRequest, 5, 1000).then(console.log);
// 第 1 次失败,1000ms 后重试...
// 第 2 次失败,1000ms 后重试...
// 成功!
练习 3:实现 Promise 顺序执行
js
/**
* 顺序执行 Promise 数组
*/
function sequence(tasks) {
// 用 reduce 构建一个 Promise 链
return tasks.reduce((prev, task) => {
return prev.then((results) => {
return task().then((result) => {
results.push(result);
return results;
});
});
}, MyPromise.resolve([]));
}
// 模拟三个网络请求
const tasks = [
() => delay(1000, '用户数据'),
() => delay(500, '订单数据'),
() => delay(800, '商品数据'),
];
sequence(tasks).then((results) => {
console.log('全部完成:', results);
// 全部完成: ['用户数据', '订单数据', '商品数据']
// 总耗时约 2300ms(串行)
// 但是输出 TypeError: MyPromise.resolve is not a function
// 这个resolve静态方法没有实现,下篇文章实现,实现了之后回过头来可以解决
});
这篇完成了一个符合 Promise/A+ 规范的完整 Promise,核心两点:
then返回新 Promise ------ 这是链式调用的基础resolvePromise解析过程 ------ 处理 thenable 递归、循环引用、多次调用等边界
现在写出来的 MyPromise 已经可以通过 872 个规范测试。但还有一些问题没解决,比如:
setTimeout是宏任务,真正的 Promise 回调是微任务,时序上有差异- 还没有实现
Promise.resolve/Promise.reject/Promise.all/Promise.race等静态方法 - 还不知道
async/await到底是怎么实现的
这些,留到下篇继续写。
面试题
第 1 题:链式调用的 return 值有什么讲究?
js
Promise.resolve(1)
.then((v) => {
console.log('then1:', v);
return v + 1;
})
.then((v) => {
console.log('then2:', v);
// 这行忘了写 return
})
.then((v) => {
console.log('then3:', v);
});
输出什么?
makefile
then1: 1
then2: 2
then3: undefined
.then() 没有 return 时,默认返回 undefined。下一个 .then 拿到的是 undefined,不是上一个的值。链式调用要传递值,每一步都得 return。
第 2 题:then 里 return Promise 会怎样?
js
Promise.resolve(1)
.then((v) => {
return new Promise((resolve) => {
setTimeout(() => resolve(v + 10), 1000);
});
})
.then((v) => {
console.log(v);
});
输出?为什么是 11 而不是 Promise 对象?
1 秒后输出:11
.then 的回调返回一个 Promise 时,后面的 .then 不会拿到这个 Promise 对象,而是等待这个 Promise resolve ,拿到 resolve 的值。这就是 resolvePromise 干了三件事中的核心:递归展开 thenable
第 3 题:then 里 return 同一个 thenable 会怎样?
js
const p = new MyPromise((resolve) => resolve(1));
const p2 = p.then(() => p2);
p2.catch((e) => console.log(e.message));
用完整版 MyPromise 跑这段代码会怎样?
输出:Chaining cycle detected
p2.then(() => p2) 让 promise2 尝试等待自己 resolve------这是一个循环引用。Promise/A+ 规范规定 x === promise2 时直接 reject(TypeError),我们在 resolvePromise 里加了这层检查。
第 4 题:错误冒泡------哪个 catch 会收到?
js
Promise.resolve(1)
.then((v) => {
console.log('A:', v);
throw new Error('爆炸');
})
.then((v) => {
console.log('B:', v);
})
.catch((e) => {
console.log('catch:', e.message);
})
.then((v) => {
console.log('C:', v);
});
输出什么?
makefile
A: 1
catch: 爆炸
C: undefined
第一个 .then 抛错后,第二个 .then(B)被跳过,错误一路冒泡到最近的 .catch。而 .catch 本身也返回一个 Promise,它吃掉了错误后 resolve(undefined),所以 C 继续打印 undefined。
第 5 题:手写题------请实现 Promise 的链式调用核心
用简单的方式解释:new Promise(...).then(...).then(...) 为什么可以一直 .then 下去?用一段伪代码说明思路。
js
// 核心思路:then 每次返回新的 Promise
then(onFulfilled, onRejected) {
const promise2 = new Promise((resolve, reject) => {
// 当前状态 settled 时,用 setTimeout 异步执行回调
if (this.state === FULFILLED) {
setTimeout(() => {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
});
}
// pending 时把回调存队列
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(() => { ... });
}
});
return promise2; // ← 关键:返回新 Promise,链才能继续
}
三个要点:
then每次返回新的 Promise(不是 this)- 回调执行结果
x通过resolvePromise展开 resolvePromise处理三种情况:普通值、thenable、循环引用
欢迎关注公众号:程序员蜡笔熊,期待与您的讨论