按顺序连续处理项目列表,并在所有完成后返回 ok(异步 -> 同步)

Processing list of items serially in order and returning ok when all is done (async -> sync)

我对 promises 和异步过程的概念感到头疼。我已经订购了一个列表,想为每个项目调用一个函数,等到第一个项目的第一个过程完成,继续第二个、第三个等等。只有在处理完每个项目后我才想继续主流程。

下面是与主进程配合良好的代码。因此返回 Q.all(promises) 导致首先处理所有承诺,然后继续主流程。但问题是,项目(导航键)是异步处理的,而我需要它们是同步的:

function processPages(that) {
  var navs = [];
  Object.keys(that.navigation).map(function(key) {
    navs.push({key: key, order: parseInt(that.navigation[key].index)});
  });
  var promises = navs.sort(function(a, b) {
    return a.order - b.order;
  })
  .map(function(item) {
    return that.parsePage(item.key).then(function(page) {
      return page.sections.filter(function(section) {
        return section.type == 'normal';
      })
      .map(function(section) {
        collectStore(section, page, that);
      });
    });
  });
  return Q.all(promises);
}

下面是我修改项目同步和正确顺序处理时的代码,但现在主进程将不同步:

function processPages(that) {
  var navs = [];
  Object.keys(that.navigation).map(function(key) {
    navs.push({key: key, order: parseInt(that.navigation[key].index)});
  });
  var promises = navs.sort(function(a, b) {
    return a.order - b.order;
  })
  .reduce(function(previous, item) {
    return previous.then(function () {
      return that.parsePage(item.key).then(function(page) {
        return page.sections.filter(function(section) {
          return section.type == 'normal';
        })
        .map(function(section) {
          collectStore(section, page, that);
        });
      });
    });
  }, Q());
  return Q.all(promises);
}

有谁知道这里发生了什么以及在这种情况下如何正确使用 promises?

附加信息

processPages 从 init 挂钩调用。如果不使用 promise (Q.all),那么 page hook 可能会在 init hook 完全处理之前触发,我也不允许这样做。这就是我所指的 "main process".

module.exports =
{
  hooks: {
    "init": function() {
      var options = this.options.pluginsConfig['regexplace'] || {};
      options.substitutes = options.substitutes || {};
      // collects text replacement queries from plugin configuration
      options.substitutes.forEach(function (option) {
        patterns.push({re: new RegExp(option.pattern, option.flags || ''), 
                       sub: option.substitute,
                       decode: option.decode || false,
                       store: option.store || null,
                       unreset: option.unreset || false});
      });
      this.config.book.options.variables = this.config.book.options.variables || {};
      processPages(this);
    },
    "page": function(page) {
      var that = this;
      // process all normal sections in page
      page.sections.filter(function(section) {
        return section.type == 'normal';
      })
      .map(function(section) {
        collectStore(section, page, that, true);
      });
      return page;
    }
  }
};

代码是 GitBook 插件代码的一部分。

查看 Understanding JavaScript Promise with Examples 中的可运行示例(来自 Chrome 的开发控制台),尤其是 "chaining" 示例。

根据您对 的描述“...我已经订购了一个列表并想调用一个包含每个项目的函数,等到第一个过程第一项完成后,进行第二项、第三项,依此类推。只有在处理完每一项后,我才想继续 主流程。",

从算法的角度来看,你应该 "chaining" 多个承诺在一起:

  • 为每个项目创建一个 Promise。当一个项目完成时,调用 resolve() 以便 then() 将执行(链中的下一个项目)。
  • 将 "main process" 作为链中的最后一项。

推荐你 test/learn promises 的执行流程,在将它应用到你的问题之前用简单的例子 - 使它更容易理解。

希望对您有所帮助! :-)

解决方案很简单,只需更改:

processPages(this);

return processPages(this);

在初始化挂钩上。