为了账号安全,请及时绑定邮箱和手机立即绑定

解决承诺一个接一个(即顺序)?

解决承诺一个接一个(即顺序)?

鸿蒙传说 2019-06-15 17:45:51
解决承诺一个接一个(即顺序)?考虑以下以串行/顺序方式读取文件数组的代码。readFiles返回承诺,只有在所有文件按顺序读取后才能解析。var readFile = function(file) {   ... // Returns a promise.};var readFiles = function(files) {   return new Promise((resolve, reject) =>      var readSequential = function(index) {       if (index >= files.length) {         resolve();       } else {         readFile(files[index]).then(function() {           readSequential(index + 1);         }).catch(reject);       }     };    readSequential(0); // Start!   });};上面的代码可以工作,但我不喜欢为了事情的顺序发生而执行递归。是否有更简单的方法可以重写这段代码,这样我就不用使用我的怪异代码了?readSequential功能?最初我试着用Promise.all但这导致了readFile调用同时发生,即不我想要的是:var readFiles = function(files) {   return Promise.all(files.map(function(file) {     return readFile(file);   }));};
查看完整描述

3 回答

?
慕工程0101907

TA贡献1887条经验 获得超5个赞

如果环境支持异步函数,我将使用它:

async function readFiles(files) {
  for(const file of files) {
    await readFile(file);
  }};

如果愿意,可以将文件的读取推迟到需要使用异步生成器(如果环境支持的话):

async function* readFiles(files) {
  for(const file of files) {
    yield await readFile(file);
  }};

更新:重新考虑一下-我可能会使用for循环来代替:

var readFiles = function(files) {
  var p = Promise.resolve(); // Q() in q

  files.forEach(file =>
      p = p.then(() => readFile(file)); 
  );
  return p;};

或更简洁地,减少:

var readFiles = function(files) {
  return files.reduce((p, file) => {
     return p.then(() => readFile(file));
  }, Promise.resolve()); // initial};

在其他承诺库(如When和Bluebird)中,您有用于此的实用方法。

例如,蓝鸟将是:

var Promise = require("bluebird");var fs = Promise.promisifyAll(require("fs"));
var readAll = Promise.resolve(files).map(fs.readFileAsync,{concurrency: 1 });
// if the order matters, you can use Promise.each instead and omit concurrency paramreadAll.then(function(allFileContents){
    // do stuff to read files.});

虽然没有任何理由今天等待使用异步。


查看完整回答
反对 回复 2019-06-15
?
波斯汪

TA贡献1811条经验 获得超4个赞

下面是我喜欢以串联方式运行任务的方式。

function runSerial() {
    var that = this;
    // task1 is a function that returns a promise (and immediately starts executing)
    // task2 is a function that returns a promise (and immediately starts executing)
    return Promise.resolve()
        .then(function() {
            return that.task1();
        })
        .then(function() {
            return that.task2();
        })
        .then(function() {
            console.log(" ---- done ----");
        });}

有更多任务的案子呢?比如,10?

function runSerial(tasks) {
  var result = Promise.resolve();
  tasks.forEach(task => {
    result = result.then(() => task());
  });
  return result;}


查看完整回答
反对 回复 2019-06-15
?
LEATH

TA贡献1936条经验 获得超6个赞

这个问题很古老,但是我们生活在一个ES6和函数式JavaScript的世界里,所以让我们看看如何改进。

因为承诺会立即执行,我们不能仅仅创建一系列的承诺,它们都会被并行触发。

相反,我们需要创建一个返回承诺的函数数组。然后,每个函数将依次执行,然后在内部启动承诺。

我们可以用几种方法解决这个问题,但我最喜欢的方法是使用reduce.

它的使用变得有点棘手reduce结合承诺,所以我已经把一个班轮分解成一些较小的可消化的咬在下面。

这个功能的本质是使用reduce起始值为Promise.resolve([])或包含空数组的承诺。

然后,这个承诺将传递给reduce方法ASpromise..这是将每个承诺依次链接在一起的关键。下一个要执行的承诺是functhen触发,将结果连接起来,然后返回该承诺,执行reduce循环下一个承诺函数。

一旦所有承诺都已执行,返回的承诺将包含每个承诺的所有结果的数组。

ES6示例(一个班轮)

/*
 * serial executes Promises sequentially.
 * @param {funcs} An array of funcs that return promises.
 * @example
 * const urls = ['/url1', '/url2', '/url3']
 * serial(urls.map(url => () => $.ajax(url)))
 *     .then(console.log.bind(console))
 */const serial = funcs =>
    funcs.reduce((promise, func) =>
        promise.then(result => func().then(Array.prototype.concat.bind(result))), Promise.resolve([]))

ES6示例(细分)

// broken down to for easier understandingconst concat = list => Array.prototype.concat.bind(list)const promiseConcat = f => x 
=> f().then(concat(x))const promiseReduce = (acc, x) => acc.then(promiseConcat(x))/*
 * serial executes Promises sequentially.
 * @param {funcs} An array of funcs that return promises.
 * @example
 * const urls = ['/url1', '/url2', '/url3']
 * serial(urls.map(url => () => $.ajax(url)))
 *     .then(console.log.bind(console))
 */const serial = funcs => funcs.reduce(promiseReduce, Promise.resolve([]))

用法:

// first take your workconst urls = ['/url1', '/url2', '/url3', '/url4']
// next convert each item to a function that returns a promiseconst funcs = urls.map(url => () => $.ajax(url))
// execute them seriallyserial(funcs)
    .then(console.log.bind(console))


查看完整回答
反对 回复 2019-06-15
  • 3 回答
  • 0 关注
  • 422 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号