使用 Bluebird promises 修复 Node.js 中的 scope/context 错误

Fixing scope/context mistake in Node.js with Bluebird promises

由于 this awesome video playlist,我认为我终于掌握了一些基本的 javascript 概念:回调、作用域和上下文不再是头疼的问题。

然后,我决定使用 promises(Node.js 中的 bluebird)...这些问题再次出现,我想我不明白范围和上下文如何与 promises 一起工作。这是我的测试 运行 :

function testit(){
  for (var i=0 ; i<3 ; i++) {
    var test = i;
    console.log(test);
    
    Promise
    .delay(5000) // do some async operations...
    .then( () => {
        console.log(test);
    });
  }
  return("finished");
}
console.log(testit());

//// What I hoped to see :
// 0, 1, 2, finished, 0, 1, 2

//// What happens :
// 0, 1, 2, finished, 2, 2, 2

我又回来了 scope/context 麻烦。为了解决这个问题,我找到了 bluebird Promise.bind(),它给了我:

function testit(){
  for (var i=0 ; i<3 ; i++) {
    var test = i;
    console.log(test);
    
    Promise
    .bind(this, test)
    .delay(5000)
    .then( (test) => {
        console.log(test);
    });
  }
  return("finished");
}
console.log(testit());

//// What happens :
// 0, 1, 2, finished, 0, 1, 2

哎呀!我有一个解决方法!但是在链接 .next() 方法时显然不方便:我必须将 test 的值从一个承诺传递到另一个承诺......在我的代码中不能这样做,我在其中链接了很多不同 functions/methods.

那么,在 Node.js 中使用 promises 时,是否有更简洁的方法从 for 循环中 "bind"/"retain some values" ?


编辑:我正在考虑循环内的承诺链的闭包:

function testit(){
  for (var i=0 ; i<3 ; i++) {
    var test = i;
    console.log(test);
    
    (function (test){
      Promise
      .delay(5000) // do some async operations...
      .then( () => {
          console.log(test);
      });
    })(test);
  }
  return("finished");
}
console.log(testit());

//// What happens :
// 0, 1, 2, finished, 0, 1, 2

它也能用,这是我迄今为止最好的代码。但我最初的问题仍然存在:是否有 better/cleaner 方法来实现最初预期的结果?


结论:接受的答案可能是管理循环内异步操作的最干净的方法。使用在循环外声明的闭包函数很可靠。感谢 Rob M. !

闭包是您最好的选择,否则 test 将绑定到父作用域(而不是 Promise 回调的作用域)并且您将继续看到 运行 时间值test,而不是您想要的通话时间值。

function getPromise(index) {
   return Promise
    .delay(5000)
    .resolve('index: ')
    .then((prefix) => {
        console.log(prefix + index);
    });
}

function testit(){
  for (var i=0 ; i<3 ; i++) {
    var test = i;
    console.log(test);
    getPromise(i);
  }
  console.log('finished');
}

.bind 是一种完全可以接受的方法,但如果它更适合您的话