Javascript 承诺链乱序执行

Javascript promise chain executing out of order

我使用 Javascript 的原生 Promise 制作了 fs.readFile 的 "promisified" 版本,它在解析时解析 JSON 文件和 returns 对象.

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,这给出了一个错误,因为用户仍然undefined,然后 user.variable2 从 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 中做错了什么?

你必须 return 每次链接的承诺:

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 在更高范围内声明时才有效。否则一旦你到达这个函数它将是未定义的。

Promise.all 更适合您的用例。您在回调中犯了一个错误:外部承诺使用 array 结果解决(与内部承诺的顺序相同),因此 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);
});

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

第一个例子

你犯了一个错误,你将 Promise 传递给 .then 方法,而实际上它总是需要一个函数。请注意,片段 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 方法,因为承诺会在您的下一个函数调用中得到解决并很好地返回。 您的代码段中的问题是承诺总是解析一个对象,在 Promise.all 的情况下,您应该期待一个数组。你实际上可以使用 es6 解构来简化你的代码:

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