Node.js异步库比较 - Q vs Async

Jac*_*son 28 javascript asynchronous node.js q

我已经将kriskowal的Q库用于一个项目(web scraper/human-activity simulator),并且已经熟悉promises,返回它们并解析/拒绝它们,并且库的基本异步控制流方法和错误抛出/捕获机制已被证明必要.

我遇到了一些问题.我的promise.then电话和我的回调都有形成金字塔的不可思议的倾向.有时它是出于范围界定的原因,有时则是为了保证某种事件的顺序.(我想我可以通过重构解决其中的一些问题,但是我想要完全避免"回调地狱".)

此外,调试非常令人沮丧.我花了很多时间来console.log找出错误和错误的来源; 在我终于找到它们之后,我将开始在那里抛出错误并将其捕捉到其他地方promise.finally,但是首先找到错误的过程是艰巨的.

此外,在我的项目中,订单很重要.我需要按顺序完成所有事情.通常我发现自己会生成函数数组,这些函数返回promises然后使用它们将它们链接起来Array.prototype.reduce,我认为不应该这样做.

以下是我使用此缩减技术的方法之一的示例:

removeItem: function (itemId) {

  var removeRegexp = new RegExp('\\/stock\\.php\\?remove=' + itemId);

  return this.getPage('/stock.php')
  .then(function (webpage) {
    var
      pageCount = 5,
      promiseFunctions = [],
      promiseSequence;

    // Create an array of promise-yielding functions that can run sequentially.
    _.times(pageCount, function (i) {
      var promiseFunction = function () {
        var
          promise,
          path;

        if (i === 0) {
          promise = Q(webpage);
        } else {
          path = '/stock.php?p=' + i;
          promise = this.getPage(path);
        }

        return promise.then(function (webpage) {
          var
            removeMatch = webpage.match(removeRegexp),
            removePath;

          if (removeMatch !== null) {
            removePath = removeitemMatch[0];

            return this.getPage(removePath)
            .delay(1000)
            // Stop calling subsequent promises.
            .thenResolve(true);
          }

          // Don't stop calling subsequent promises.
          return false;

        }.bind(this));
      }.bind(this);

      promiseFunctions.push(promiseFunction);
    }, this);

    // Resolve the promises sequentially but stop early if the item is found.
    promiseSequence = promiseFunctions.reduce(function (soFar, promiseFunction, index) {
      return soFar.then(function (stop) {
        if (stop) {
          return true;
        } else {
          return Q.delay(1000).then(promiseFunction);
        }
      });
    }, Q());

    return promiseSequence;
  }.bind(this))
  .fail(function (onRejected) {
    console.log(onRejected);
  });
},
Run Code Online (Sandbox Code Playgroud)

我有其他方法基本上做同样的事情,但遭受更糟糕的缩进困境.

我正在考虑使用coalan的异步库来重构我的项目.它似乎与Q类似,但我想确切地知道它们的区别.我得到的印象是异步更多"回调为中心",而Q是"以承诺为中心".

问题:鉴于我的问题和项目要求,使用异步超过Q会获得和/或失去什么?图书馆如何比较?(特别是在顺序执行一系列任务和调试/错误处理方面?)

Jac*_*son 18

两个图书馆都很好.我发现它们有不同的用途,可以串联使用.

Q为开发人员提供了promise对象,这些对象是未来的值表示.适合时间旅行.

Async为开发人员提供了控制结构和聚合操作的异步版本.

来自linter实现的一次尝试的示例展示了库之间的潜在统一:

function lint(files, callback) {

    // Function which returns a promise.
    var getMerged = merger('.jslintrc'),

        // Result objects to invoke callback with.
        results = [];

    async.each(files, function (file, callback) {
        fs.exists(file, function (exists) {

            // Future representation of the file's contents.
            var contentsPromise,

                // Future representation of JSLINT options from .jslintrc files.
                optionPromise;

            if (!exists) {
                callback();
                return;
            }

            contentsPromise = q.nfcall(fs.readFile, file, 'utf8');
            optionPromise = getMerged(path.dirname(file));

            // Parallelize IO operations.
            q.all([contentsPromise, optionPromise])
                .spread(function (contents, option) {
                    var success = JSLINT(contents, option),
                        errors,
                        fileResults;
                    if (!success) {
                        errors = JSLINT.data().errors;
                        fileResults = errors.reduce(function (soFar, error) {
                            if (error === null) {
                                return soFar;
                            }
                            return soFar.concat({
                                file: file,
                                error: error
                            });
                        }, []);
                        results = results.concat(fileResults);
                    }
                    process.nextTick(callback);
                })
                .catch(function (error) {
                    process.nextTick(function () {
                        callback(error);
                    });
                })
                .done();
        });
    }, function (error) {
        results = results.sort(function (a, b) {
            return a.file.charCodeAt(0) - b.file.charCodeAt(0);
        });
        callback(error, results);
    });
}
Run Code Online (Sandbox Code Playgroud)

我想为每个文件做一些可能阻塞的事情.这async.each是显而易见的选择.我可以并行化相关的操作每一次迭代q.all和它们是否适用于2个或多个文件重用我的选项值.

这里,Async和Q各自影响程序的控制流程,Q表示将来某个时候解析为文件内容的值.这些图书馆合作得很好.一个人不需要"选择一个而不是另一个".