【问题标题】:NodeJS callback in a for-loop value is the samefor循环值中的NodeJS回调是相同的
【发布时间】:2016-04-18 19:59:22
【问题描述】:

我在清理我的代码时遇到了一些回调问题,特别是在调用回调时要输出正确的值。可以向我解释为什么下面的代码会吐出我不期望的东西和可能的解决方案,而不必将 i 的另一个参数放入 run() 函数,或者传入 i在调用回调时知道我的索引是执行此操作的唯一方法吗?

for (var i in dls) {
    run(dls[i][0], dls[i][1], function(isTrue){
        if (isTrue) {
            // Do true stuff here
        } else {
            console.log("Value is: " + dls[i][3])
        }
    });
}

调用 run() 实际上在内部有正确的输入,但是在该函数调用回调并进入 else 语句时,dls[i][3] 会输出 i 次相同的值。

我尝试在 (run()) 等周围放置不同的范围,但无济于事,似乎无法解决这个问题。

谢谢

编辑:

如果我想把它拆分成一个单独的函数,我该怎么做?

var run = function(cb){
    setTimeout(function() {
        cb(false)
    }, 3000);
}

for (var i in dls) {
    run(dls[i][0], dls[i][1], (function(index) {
        return extraction
    })(i));
}

function extraction(isTrue){
    if (isTrue) {
        // stuff
    } else {
        console.log("Nothing changed in " + dls[i][3])
    }
}

这里 dls[i][3] 仍然不正确,打印了 3 次相同的值。

【问题讨论】:

标签: javascript node.js callback


【解决方案1】:

你掉进了传统的“循环陷阱”

当您的回调运行时,i 现在是一个不同的值。

您可以做的是将该值缓存在另一个包装函数中:

for (var i in dls) {
    run(dls[i][0], dls[i][1], (function (currentIndex) { 
        return function(isTrue){
            if (isTrue) {
                // Do true stuff here
            } else {
                console.log("Value is: " + dls[currentIndex][3])
            }
        };
    })(i));
}

【讨论】:

  • 感谢您的回复!好的,对此进行跟进。假设我不想每次迭代都创建一个新函数。函数提取(isTrue){ console.log(dls[i][3]) } for (var i in dls) { run(dls[i][0], dls[i][1], (function(index) {返回提取})(i));为什么这不起作用?
  • 因为您的回调发生在稍后 i 已设置为不同值时。
  • 嗯,我如何将缓存的值传递给函数,而不必通过回调传递它?还是我现在必须这样做?
  • 函数末尾的i实际上是函数调用内部的一个参数。由于i 的值被传递给函数,而不是仅在内部回调中引用原始i,它将是您期望的值。您还可以考虑在 ES6 中使用 let,这样可以在不需要 IIFE 的情况下解决问题。更多阅读here.
  • 非常有帮助和有用的阅读,感谢@dvlsg,今天学到了新东西!
【解决方案2】:

关于编辑/第二个问题,假设这是您想要做的:

// note that I changed the function signature of `run`
var run = function(val1, val2, cb) {
    setTimeout(function() {
        cb(false);
    }, 3000);
};

// note the `wrapper` here
for (var i in dls) {
    run(dls[i][0], dls[i][1], wrapper(i));
}

// this is the same as what the IIFE is doing,
// just with an external function instead
function wrapper(scopedIndex) {

    // return a function to be used as the callback for `run`
    return function extraction(isTrue) {
        if (isTrue) {
            // stuff
        }
        else {
            // use the scoped index here
            console.log("Nothing changed in " + dls[scopedIndex][3]);
        }
    }
}

看看另一个linked question 中的function makeExitCallback(i)。它与这里发生的事情直接相关。

您也应该发布 dls 中的内容,以便更轻松地在本地运行您的 sn-ps。

【讨论】:

  • 我写了一些与此类似的东西!我发现我遇到这么多麻烦的原因是因为我没有真正理解IIFE的概念。我读了这个gregfranko.com/blog/i-love-my-iife,告诉我每个组件是什么非常有帮助。感谢 dvlsg 的指针。 :-)
  • 是的,IIFE 似乎总是让新的 JS 开发者感到惊讶。当我第一次看到一个时,他们肯定让我很困惑。很高兴你把它整理好了。
  • 再次感谢。稍微练习一下,说不定还能教别人,哈哈。我不确定要搜索关于这个问题的确切内容,但看起来需要 6 个小时,而且我只需要一个有用的指南来找到关于 IIFE 的所有内容。
猜你喜欢
  • 1970-01-01
  • 2021-05-28
  • 2018-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
相关资源
最近更新 更多