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

Node.js+Socket.io中for循环内setInterval仅触发一次问题排查

问题原因与解决方案

问题根源

你遇到的是JavaScript闭包与var作用域的经典问题:

  • 用var声明的i是函数级作用域,整个startGame函数里只有一个i变量。
  • setInterval的回调是异步执行的,等回调触发时,外层的for...in循环已经全部执行完毕,此时i的值已经变成了lobby.players里最后一个玩家的键,所以所有定时器都会去操作最后一个玩家,看起来就像只有第二个玩家的定时器生效。

解决办法

有三种简单的修复方式,任选其一即可:

1. 用let替代var

let是块级作用域,每次循环都会创建一个独立的i变量,确保回调能捕获到当前循环的玩家键:

function startGame(lobby) {
    for (let i in lobby.players) { // 把var改成let
        console.log(lobby.players[i].id)
        lobby.players[i].emit('startGame', {
            map: lobby.map,
        });
        lobby.players[i].update = setInterval(function() {
            lobby.players[i].emit('update', getUpdatePackage(lobby));
            console.log("update " + lobby.players[i].id)
        }, 1000 / gameConfig.FPS)
        console.log(lobby.players[i].update)
    }
    console.log("Game in lobby " + lobby.id + " is starting.")
}

2. 用立即执行函数(IIFE)绑定当前i

通过IIFE把当前循环的i封装到独立作用域里:

function startGame(lobby) {
    for (var i in lobby.players) {
        console.log(lobby.players[i].id)
        lobby.players[i].emit('startGame', {
            map: lobby.map,
        });
        // 用IIFE保存当前i的值
        (function(currentI) {
            lobby.players[currentI].update = setInterval(function() {
                lobby.players[currentI].emit('update', getUpdatePackage(lobby));
                console.log("update " + lobby.players[currentI].id)
            }, 1000 / gameConfig.FPS)
        })(i)
        console.log(lobby.players[i].update)
    }
    console.log("Game in lobby " + lobby.id + " is starting.")
}

3. 遍历玩家对象的值(更直观)

把玩家对象转成数组后用forEach遍历,直接拿到每个玩家实例,避免键的问题:

function startGame(lobby) {
    // 把对象转成值数组,遍历每个玩家
    Object.values(lobby.players).forEach(player => {
        console.log(player.id)
        player.emit('startGame', {
            map: lobby.map,
        });
        player.update = setInterval(function() {
            player.emit('update', getUpdatePackage(lobby));
            console.log("update " + player.id)
        }, 1000 / gameConfig.FPS)
        console.log(player.update)
    })
    console.log("Game in lobby " + lobby.id + " is starting.")
}

内容的提问来源于stack exchange,提问作者Martin Brůžek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:15:02