【问题标题】:Javascript promise chain executing out of orderJavascript 承诺链无序执行
【发布时间】:2016-12-13 00:54:00
【问题描述】:

我使用 Javascript 的原生 Promise 制作了 fs.readFile 的“承诺”版本,它解析 JSON 文件并在解析时返回对象。

function readFileAsync(file, options) {
  return new Promise(function (resolve, reject) {
    fs.readFile(file, options, function(err, data) {
      if (err) {
        reject(err);
      } else {
        var object = JSON.parse(data);
        resolve(object);
      }
    });
  });
}

我首先尝试自己链接承诺,但由于某种原因,首先来自承诺 1 的 districts.variable1 被记录,然后在承诺 3 中调用 comparePersonalities,这会给出错误,因为用户仍未定义,然后是 @987654325 @ 从 promise 2 中记录。

var user, district;
readFileAsync(file1, 'utf8').then(function (data) {
  districts = data;
  console.log(districts.variable1);
}).then(readFileAsync(file2, 'utf8').then(function (data) {
  user = data;
  console.log(user.variable2);
})).then(function (result) {
  comparePersonalities(districts, user);
}).catch(function (e) {
  console.log(e);
});

我还尝试了使用Promise.all 的替代方法,但这仍然会导致错误的排序和comparePersonalities 失败。

Promise.all([readFileAsync(file1), readFileAsync(file2)]).then(function (first, second) {
  districts = first;
  user = second;
  comparePersonalities(districts, user);
});

当在 Promise 中记录已解析的对象时,一切似乎都运行良好,我无法弄清楚为什么一切最终都被初始化,但最后一个 Promise 在第二个 Promise 完成之前运行。我在链式承诺和Promise.all 中做错了什么?

【问题讨论】:

  • then(readFileAsync 是错误的。从那里开始。
  • 你不能将promise (readFileAsync(file2, 'utf8').then(…)) 传递给then,你需要传递一个函数!

标签: javascript node.js promise chaining


【解决方案1】:

Promise.all 更适合您的用例。您在回调中犯了一个错误:外部 promise 使用 array 结果解析(与内部 promise 的顺序相同),因此 then(function (first, second) {...}) 不正确。试试这样的

Promise.all([
  readFileAsync(file1, 'utf8'),
  readFileAsync(file2, 'utf8')
]).then(function (results) {
  // note that "results" is an array of two values
  var districts = results[0];
  var user = results[1];
  comparePersonalities(districts, user);
});

【讨论】:

    【解决方案2】:

    Promise 总是只使用 一个 值来解决。这真的很重要,而且实际上简化了很多事情,因为您总是知道需要多少元素。

    第一个例子

    您犯了一个错误,您将 Promise 传递给 .then 方法,而实际上它总是需要一个函数。请注意,sn-p readFileAsync(file2, 'utf8') 很好地包装在一个匿名函数中。

    var user, district;
    readFileAsync(file1, 'utf8').then(function (data) {
      districts = data;
      console.log(districts.variable1);
    })
      .then(function () { return readFileAsync(file2, 'utf8') })
      .then(function (data) {
        user = data;
        console.log(user.variable2);
      }).then(function (result) {
        comparePersonalities(districts, user);
      }).catch(function (e) {
        console.log(e);
      });
    

    第二个例子

    但是,在这种情况下,您可能最好使用Promise.all 方法,因为承诺会在您的下一个函数调用中得到解决并很好地返回。 你的 sn-p 中的问题是承诺总是解决一个对象,在Promise.all 的情况下,你应该期待一个单一的数组。您实际上可以使用 es6 解构来简化您的代码:

    Promise.all([readFileAsync(file1), readFileAsync(file2)])
      .then(function ([districts, user]) {
        comparePersonalities(districts, user);
      });
    

    【讨论】:

      【解决方案3】:

      你必须每次都返回 Promise 以进行链接:

      readFileAsync(file1, 'utf8').then(function(data) {
          districts = data;
          console.log(districts.variable1);
          return readFileAsync(file2, 'utf8');
      }).then(function(data) {
          user = data;
          console.log(user.variable2);
          comparePersonalities(districts, user);
      }).catch(function(e) {
          console.log(e);
      });
      

      comparePersonalities(districts, user) 仅在您的变量 districts 在更高范围内声明时才有效。否则一旦你到达这个函数,它将是未定义的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-14
        • 1970-01-01
        • 2015-12-23
        相关资源
        最近更新 更多