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

Vue2长轮询更新数据无变化但watch仍触发问题求解

Vue2长轮询更新状态时watch重复触发解决方案

问题根因为引用类型赋值触发watch的机制导致的:每次请求返回后你直接将ffGameState赋值为全新的response.data对象,哪怕两个对象内容完全一致,内存引用地址已经发生变化。Vue2监听引用类型时,只要引用地址变更就会触发watch回调,你打印时看到val和oldVal内容一致,是因为Vue2在引用类型的watch回调中,oldVal和val指向同一个引用,并非真的内容没有变更。

可选解决方案

方案1:更新状态前做全局值对比

仅当接口返回的新数据和当前状态内容不一致时才赋值,从根源避免无意义的更新触发:

loadFfGameState() {
    this.$http
    .get("/gamestates/ff")
    .then(response => {
        // 用lodash的isEqual做深度内容对比,不一致才更新
        if (!_.isEqual(response.data, this.ffGameState)) {
            this.ffGameState = response.data
        }
    })
    .then(() => {
        setTimeout(() => this.loadFfGameState(), 100)             
    })
}

该方案改动量最小,适合状态字段不多的场景。

方案2:watch回调内加内容校验

如果不想修改请求更新逻辑,直接在watch中增加判断,内容无变化时直接跳过业务逻辑:

watch: {
    "ffGameState.errors.team1": {
        deep: true,
        handler: function(val, oldVal) {
            // 内容一致直接返回,不执行后续逻辑
            if (_.isEqual(val, oldVal)) return
            // 原有业务逻辑写在下方
            console.log("change detected")
            console.log(val)
        }
    }
}

方案3:精细化更新对应字段

不需要整对象替换ffGameState,仅单独更新需要变动的字段,更新前对该字段做内容对比:

loadFfGameState() {
    this.$http
    .get("/gamestates/ff")
    .then(response => {
        const newTeam1 = response.data?.errors?.team1
        // 仅对比你监听的team1字段,性能更优
        if (newTeam1 && !_.isEqual(newTeam1, this.ffGameState.errors.team1)) {
            this.ffGameState.errors.team1 = newTeam1
        }
        // 其他需要更新的字段参照该逻辑单独处理
    })
    .then(() => {
        setTimeout(() => this.loadFfGameState(), 100)             
    })
}

该方案性能最优,适合状态字段多、仅部分字段需要监听变更的场景。

内容的提问来源于stack exchange,提问作者LocoMH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 01:45:03