Node.jsasynchronous库比较 – Q vsasynchronous

我已经使用kriskowal的Q库作为一个项目(网页刮板/人类活动模拟器),并已经熟悉了承诺,返回并解决/拒绝了它们,图书馆的基本asynchronous控制stream方法和错误捕获/捕获机制已经被证实必要。

我遇到了一些问题。 我的promise.then电话和我的callback有形成金字塔的不可思议的倾向。 有时候是为了确定范围的原因,有时是为了保证一定的事件顺序。 (我想我可以通过重构来解决其中的一些问题,但是我希望完全避免“callback地狱”)。

另外,debugging非常令人沮丧。 我花了很多时间console.log我的方式来错误和错误的来源; 在我终于find它们之后,我将开始在那里抛出错误,并以最终的promise.finally将它们捕捉到别的地方,但把错误定位在首位的过程是艰巨的。

另外,在我的项目中, 订单很重要 。 我需要按顺序做很多事情。 通常我会发现自己生成的函数数组返回promise,然后使用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); }); }, 

我有其他的方法基本上是一样的东西,但遭受更严重的缩进困境。

我正在考虑使用coalan的asynchronous库重构我的项目。 这似乎与Q类似,但我想知道它们究竟有何不同。 我得到的印象是asynchronous更多的“callback中心”,而Q是“以承诺为中心”。

问题:鉴于我的问题和项目需求,通过在Q上使用asynchronous,我会获得和/或失去什么? 图书馆如何比较? (特别是在顺序执行一系列任务和debugging/error handling方面?)

两个图书馆都很好。 我发现他们服务于不同的目的,可以一起使用。

Q为开发人员提供承诺对象,这些对象是未来的值表示。 有用的时间旅行。

Async为开发人员提供控制结构和聚合操作的asynchronous版本。

从一个棉绒实施尝试的例子表明了图书馆之间的潜在的统一:

 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); }); } 

我想为每个文件做一些潜在的阻塞操作。 所以async.each是明显的select。 我可以将每次迭代的 相关操作与q.all ,如果它们适用于2个或多个文件,则可以重用我的选项值。

这里,Async和Q各自影响程序的控制stream程,Q表示将来某个时间parsing文件内容的值。 图书馆一起工作。 一个不需要“select一个”。

你的代码中的callback金字塔可以使用promise组合和javascript词法范围来简化。

 removeItem: function (itemId) { var removeRegexp = new RegExp('\\/stock\\.php\\?remove=' + itemId); var found = false var promise = getPage('/sock.php') _.times(5, (i) => { promise = promise.then((webpage) => { if (found) return true var removeMatch = webpage.match(removeRegexp) var found = removeMath !== null var nextPage = found ? removeMatch[0] : '/stock.php?p='+i+1 return Q.delay(1000).then(() => this.getPage(nextPage)) }) }) return promise.fail(console.log.bind(console)) }, 

恕我直言, async不应该在新的JavaScript代码中使用。 承诺更可组合,并允许更多直觉式的代码。

节点没有使用承诺的主要原因是由于性能方面的问题,Bluebird和Q等图书馆在很大程度上解决了这个问题。

随着asynchronous/等待语法变得更加主stream,承诺将为代码看起来与同步代码非常相似铺平道路。

虽然这仍然不是我的问题 (Q vsasynchronous)的实际答案,关于我的问题 ,我发现Selenium / WebDriverJs是一个可行的解决scheme。

 driver.get('http://www.google.com'); driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); driver.findElement(webdriver.By.name('btnG')).click(); driver.wait(function() { return driver.getTitle().then(function(title) { return title === 'webdriver - Google Search'; }); }, 1000); 

WebDriver使用队列顺序执行promise,这有助于控制缩进。 其承诺也与Q's兼容。

创build一系列的承诺不再是一个问题。 一个简单的for循环会做。

至于在一个序列的早期停止,不要这样做。 使用asynchronousdevise和分支,而不是使用序列。