我曾经在一个项目(网络爬虫/人类活动模拟器)中使用过 kriskowal的Q库,并且熟悉了Promise、如何返回Promise以及如何解决/拒绝Promise。该库的基本异步控制流方法和错误抛出/捕获机制已被证明是必不可少的。
然而,我遇到了一些问题。我的promise.then调用和回调函数有时倾向于形成金字塔结构。有时是由于作用域的原因,有时是为了保证一定的事件顺序。(我想通过重构来解决这些问题,但今后我希望完全避免“回调地狱”)
此外,调试非常令人沮丧。我花了很多时间用console.log寻找错误和漏洞的源头;当我最终找到它们时,我会在那里抛出错误,并在其他地方使用promise.finally捕获它们,但首先定位错误的过程是艰难的。
此外,在我的项目中,顺序很重要。我几乎需要按顺序执行所有操作。往往我会生成返回Promise的函数数组,然后使用Array.prototype.reduce将它们链接在一起,但我认为我不应该这样做。
下面是我使用此缩减技术的方法之一的示例:
然而,我遇到了一些问题。我的promise.then调用和回调函数有时倾向于形成金字塔结构。有时是由于作用域的原因,有时是为了保证一定的事件顺序。(我想通过重构来解决这些问题,但今后我希望完全避免“回调地狱”)
此外,调试非常令人沮丧。我花了很多时间用console.log寻找错误和漏洞的源头;当我最终找到它们时,我会在那里抛出错误,并在其他地方使用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的async库 重构我的项目。它看起来与Q类似,但我想知道它们之间的确切区别。我得到的印象是,async更加“回调中心”,而Q则是“承诺中心”。
问题:鉴于我的问题和项目要求,如果使用async而不是Q,我会获得什么,失去什么?这两个库有什么区别?(特别是在按顺序执行一系列任务和调试/错误处理方面?)
.series
和.eachSeries
。当然,.then链也可以实现相同的目标。 - Kevin B