如何用Promise链式调用改写代码?改写后无法输出预期结果29
问题分析与解决方案
问题原因
改写后的Promise链式调用存在作用域丢失的问题:
- 第一个
then的回调参数res1仅在该回调内部有效,后续then无法访问 - 第二个
then的res2是getSmth(3)的返回值(9),同样只在当前回调内部有效 - 最后一个
then里的res1、res2都是未定义变量,仅res3是getSmth(4)的返回值(16),最终计算undefined + undefined + 16得到NaN,无法输出预期的29
解决方案
方案1:链式传递中间结果(保持顺序执行)
如果需要保留原代码的顺序执行逻辑(先执行getSmth(2),再3,最后4),可以在每个then中把之前的结果和当前Promise的返回值一起传递:
function getSmth(num) { return new Promise((resolve, reject) => { setTimeout(() => resolve(num * num), 500) }); } function func() { getSmth(2) .then(res1 => getSmth(3).then(res2 => [res1, res2])) .then(([res1, res2]) => getSmth(4).then(res3 => [res1, res2, res3])) .then(([res1, res2, res3]) => { console.log(res1 + res2 + res3); // 输出29 }) } func();
也可以用变量缓存中间结果:
function func() { let res1, res2; getSmth(2) .then(r1 => { res1 = r1; return getSmth(3); }) .then(r2 => { res2 = r2; return getSmth(4); }) .then(r3 => { console.log(res1 + res2 + r3); // 输出29 }) }
方案2:用Promise.all并行执行(更高效)
由于三个getSmth调用无依赖关系(不需要前一个结果作为后一个的参数),可以用Promise.all同时发起请求,总耗时仅500ms(顺序执行需1500ms):
function getSmth(num) { return new Promise((resolve, reject) => { setTimeout(() => resolve(num * num), 500) }); } function func() { Promise.all([getSmth(2), getSmth(3), getSmth(4)]) .then(([res1, res2, res3]) => { console.log(res1 + res2 + res3); // 输出29 }) } func();
方案3:使用async/await(简洁易读)
如果环境支持ES2017+,用async/await语法糖会更直观:
function getSmth(num) { return new Promise((resolve, reject) => { setTimeout(() => resolve(num * num), 500) }); } async function func() { const res1 = await getSmth(2); const res2 = await getSmth(3); const res3 = await getSmth(4); console.log(res1 + res2 + res3); // 输出29 } func();
并行执行版本:
async function func() { const [res1, res2, res3] = await Promise.all([getSmth(2), getSmth(3), getSmth(4)]); console.log(res1 + res2 + res3); // 输出29 }
内容的提问来源于stack exchange,提问作者Евгений Черник
相关产品推荐
相关产品推荐

