如何向Promise的then方法传参?循环内then回调获取q值为undefined
问题原因
这是var声明的函数级作用域和异步回调执行时序共同导致的经典问题:
- 用
var声明的循环变量q属于整个外层函数作用域,不存在循环块级的独立绑定,所有异步回调共享同一个q变量 - 循环本身是同步执行的,会一次性发起所有
sendFetch请求,等请求返回触发then回调时,循环早已执行完毕,此时q已经是循环终止时的值,你观测到undefined本质是回调执行时没有拿到对应循环轮次的变量值 - 之前直接把
q作为参数传入then不生效,是因为Promise.prototype.then的入参只接受回调函数,传入普通变量不会被注入到回调的执行上下文。
解决方案
以下三种方案可直接落地,按需选择即可:
方案1:将var替换为let(最简便)
let是块级作用域,每一轮循环都会生成独立的q绑定,每个回调能拿到对应循环轮次的正确q值:
myfunction = () =>{ sendFetch( `http://api.com`, GET ).then((response)=>{ for (var i = 0; i < response.data.length; i++) { processed_data.push(response.data[i].description); } // 仅需把此处var改为let for (let q = 0 ; q < array.length; q++) { sendFetch( `api.com`, GET ).then((response)=>{ console.log(q) // 会按顺序输出对应轮次的0、1、2... }) } }) }
方案2:通过闭包锁定每轮循环的q值
如果运行环境不支持let,可以用立即执行函数给每轮循环创建独立作用域,固化当前轮次的q值:
for (var q = 0 ; q < array.length; q++) { (function(currentQ){ sendFetch( `api.com`, GET ).then((response)=>{ console.log(currentQ) }) })(q) }
方案3:用Promise.all统一处理请求(推荐,逻辑更易维护)
如果不需要按顺序串行发请求,用Promise.all等所有请求返回后再统一处理,能避免回调嵌套问题:
myfunction = () =>{ sendFetch( `http://api.com`, GET ).then(async (response)=>{ for (var i = 0; i < response.data.length; i++) { processed_data.push(response.data[i].description); } // 生成所有请求的Promise数组 const requestList = array.map((_, q) => sendFetch(`api.com`, GET)) // 等待所有请求返回,结果顺序和原数组顺序一一对应 const results = await Promise.all(requestList) results.forEach((res, q) => { console.log(q) // 对应循环序号 // 在此处编写每个请求返回后的处理逻辑即可 }) }) }
补充:如果需要按顺序串行发送请求,不要用
Promise.all,可以改用for await结构,或者通过reduce串联Promise链实现。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

