You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Promise.all从Redis赋值后局部变量未更新问题求助

问题排查

核心原因

  • 循环变量未做块级作用域绑定:所有for循环里的i都没有声明,属于隐式全局变量,所有异步回调引用的都是同一个i。当Promise的回调执行时,同步循环已经跑完,i的值已经变成了4,你实际赋值和打印的是自动创建的全局变量b4,原来的b1/b2/b3从未被修改过。你在then回调里看到的打印结果实际是b4的三次更新输出,并不是b1/b2/b3的值,属于认知偏差。
  • 次要隐患:Redis的写入操作client.set是异步API,你没有等待写入完成就发起读取请求,高延迟场景下可能出现读不到数据的问题。
  • 不推荐使用eval:既存在安全风险,也容易引发作用域相关的意外问题,完全可以用数组/对象存储变量替代。

修复方案

最优写法(移除eval,优化结构)

// 用数组存储三个结果,不需要单独声明b1/b2/b3
let b = [[], [], []]
// 把redis的回调API转为Promise风格,方便用async/await
const { promisify } = require('util')
const setRedis = promisify(client.set).bind(client)
const getRedis = promisify(client.get).bind(client)

async function start(){
    // 等待所有Redis写入完成再读数据
    let data = []
    const writePromises = []
    for(let i=1; i<=3; i++){
        data.push(i)
        writePromises.push(setRedis('a'+i, JSON.stringify(data)))
    }
    await Promise.all(writePromises)

    // 并发读取所有Redis数据
    const readPromises = []
    for(let i=1; i<=3; i++){
        readPromises.push(getRedis('a'+i))
    }
    const results = await Promise.all(readPromises)
    // 把结果赋值到b数组
    results.forEach((res, index) => {
        b[index] = JSON.parse(res)
        console.log(b[index])
    })

    // 这里直接用b数组即可,索引0对应原b1,1对应原b2,2对应原b3
    console.log('所有结果:', b)
}

start()

保留b1/b2/b3变量的兼容写法

只需要给所有循环的i加上let声明,绑定块级作用域即可:

let b1 = [] 
let b2 = []
let b3 = []
const { promisify } = require('util')
const setRedis = promisify(client.set).bind(client)
const getRedis = promisify(client.get).bind(client)

async function start(){
    let data = []
    const writePromises = []
    // 给i加let声明
    for(let i=1; i<=3; i++){
        data.push(i)
        writePromises.push(setRedis('a'+i, JSON.stringify(data)))
    }
    await Promise.all(writePromises)

    let arrayX = []
    // 给i加let声明
    for(let i=1; i<=3; i++){
        arrayX.push(getRedis('a'+i).then(result => {
            eval('b'+i + '=' + result)
            console.log(eval('b'+ i))
        }))
    }
    await Promise.all(arrayX).then(()=>{
        // 给i加let声明
        for(let i=1; i<=3; i++){
            console.log(eval('b'+ i))
        }
    })
}

start()

内容的提问来源于stack exchange,提问作者Pranjal Pratim Hazarika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 16:06:11