你如何同步解决一系列 es6 承诺?

How do you synchronously resolve a chain of es6 promises?

我有一个图书馆的功能,returns 一个承诺。我需要多次运行这个函数,但是每次迭代都必须等到上一个任务完成。

我的假设是我可以做到这一点:

promiseReturner(1)
  .then(promiseReturner(2)
  .then(promiseReturner(3)
  .then(...)

可以使用循环来简化:

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
  p = p.then(promiseReturner(i));
}

然而,当我这样做时,链中的每个承诺都会同时执行,而不是像 .then() 似乎暗示的那样一个接一个地执行。显然,我遗漏了一些关于 promises 的基本知识——但在阅读了几篇教程和博客文章后,我仍然迷失了方向。

Here's a codepen I wrote up to demonstrate my attempt.

您的 "non-loop" 解决方案也不应该有效。您必须将 函数 传递给 .then,而不是承诺:

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
  (function(i) {
      p = p.then(function() {
          return promiseReturner(i);
      });
  }(i));
}

如果那个函数 returns 是一个承诺,那么你就会得到那种连锁效应。[​​=18=]

关于 MDN 的承诺的更多信息。


可以用let(和箭头函数)简化:

var p = Promise.resolve();
for (let i=1; i<=10; i++) {
    p = p.then(() => promiseReturner(i));
}

.bind(即ES5):

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
    p = p.then(promiseReturner.bind(null, i));
}

您可以使用 async/await 使用 es6 生成器和 co 这样的库。

co(function* () {
  while(upto < 10) {
    var result = yield Promise.resolve(true);
  }
  return result;
}).then(function (value) {
  console.log(value);
}, function (err) {
  console.error(err.stack);
});

这里详细介绍了它的工作原理:http://davidwalsh.name/async-generators

这是我用来解决相同问题的解决方案:

var recursiveFunction = function(values) {
  return new Promise(function(resolve, reject) {
    if (values.length <= 0) {
        return resolve();
    } else {
        return promiseReturner(values[0]).then(function() {
            values.shift();
            return recursiveFunction(values).then(function() {
              resolve();
            });
        });
      }
  });
}

recursiveFunction([1,2]).then(function(r) {
 console.warn('Finished solving promises sequentially');
})

如果您使用的是 es6,则可以使用 array.reduce 实现此目的。我想的还挺整齐的。

const functions = [/* array of functions which return promises */];
const finalPromise = functions.reduce(async (promise, asyncFn) => {
  await promise;
  return asyncFn();
}, Promise.resolve());

您可以通过 nsynjs 运行 您的代码,它将暂停执行 returns 承诺的每个函数,并等待承诺得到解决:

var promiseReturner = function(i) {
    return new Promise(function(resolve, reject) {
        setTimeout(function(){
            resolve("result is "+i)
        }, 1000);
    });
};

function synchronousCode() {
    for (var i=1; i<=10; i++) {
        var p=promiseReturner(i); // nsynjs will pause here until promise is resolved
        console.log(p.data); // `data` will contain result of the promise
    }
};
 
nsynjs.run(synchronousCode, null, function(){
 console.log("finish");
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

彼此同步执行承诺可能很棘手。我在下面包含了一个使用 Axios 承诺的示例,但您可以用自己的承诺替换它们。祝你好运!

const get = (endpoint = '/', params = {}) => {
  // return axios promise
  return axios({
    method: 'get',
    url: apiHost + endpoint,
    headers: { 'Authorization': 'Token ' + this.state.token },
    params: params,
  });
};

get('/api/some-endpoint/')
  .then((response) => {
    console.log(response);
    //return next promise
    return get('/api/another-endpoint/');
  }).then((response) => {
    console.log(response);
    // return next promise
    return get('/api/yet-endpoint');
  }).then((response) => {
    console.log(response);
    // return next promise
    return get('/api/last-endpoint/');
  }).then((response) => {
    console.log(response);
    // finished, no more promises left in the chain
  })
  .catch(function (error) {
    console.log('Error getting data', error);
  });