首先,ups.track() 是一个异步函数。这意味着它将在未来某个不确定的时间调用其回调。因此,您的 for 循环运行完成,启动 result.length 对 ups.track() 的调用,然后在它们中的任何一个完成之前执行 res.send(result),在它们中的任何一个调用回调之前。
其次,您没有初始化 test 变量,因此 test += ... 不会产生好的结果。
因此,在所有结果都完成之前,您无法知道结果。有多种方法可以做到这一点。
低技术计数器
做到这一点的“低技术”方法是保持计数器:
var test = "";
var cntr = 0;
for(var i = 0; i < result.length; i++) {
var currentNumber = result[i].trackingNumber;
ups.track(currentNumber, function(err, tracking) {
test += tracking;
// see if we are done with all the ups.track() calls yet
if (++cntr === result.length) {
res.send(test);
}
});
}
使用承诺
更高技术的方法是使用 Promise(由于许多其他原因,这对学习有更大的好处)。虽然 Promise 在这里只显示出适度的好处,但只要您有需要协调的异步操作序列,它们就会提供巨大的好处,并且它们还可以使错误处理(您在代码示例中忽略的事情)变得更加简单。
首先,您创建一个“承诺”版本的ups.track(),这是一个返回承诺的函数,当ups.track() 完成时,该承诺将解决或拒绝。
function upsTrack(num) {
return new Promise(function(resolve, reject) {
ups.track(num, function(err, tracking) {
err ? reject(err) : resolve(tracking);
});
});
}
现在,我们将使用.map() 的组合从您对upsTrack() 和Promise.all() 的所有调用中创建一个数组或承诺,以告诉我们所有这些承诺何时完成。
Promise.all(result.map(function(item) {
return upsTrack(item.trackingNumber);
})).then(function(allResults) {
// allResults is an array of tracking results
// process that array into your final result and send it
res.send(allResults.join(","));
}).catch(function(err) {
// handle error here
res.status(500).end();
});
请注意,此结构还消除了在以前的低技术方式中定义的多个变量,因为不再需要 test、cntr 或 i。处理数组或处理结果数组的循环结构和函数为我们解决了所有这些问题。
使用 Bluebird Promise 库
而且,您甚至可以通过使用像 Bluebird 这样更智能的 Promise 库来走更多捷径:
const Promise = require('bluebird');
ups = Promise.promisifyAll(ups);
Promise.map(result, function(item) {
return ups.trackAsync(item.trackingNumber);
}).then(function(allResults) {
// allResults is an array of tracking results
// process that array into your final result and send it
res.send(allResults.join(","));
}).catch(function(err) {
// handle error here
res.status(500).end();
});
Bluebird Promise 库在这里有两个有用的东西。它有一个promisifyAll() 方法,它会自动为你生成所有ups 对象方法的promisified 方法,它还有Promise.map(),它只是将array.map() 和Promise.all() 组合在一个步骤中(因为它是一种常用的结构)。
如果您对 Promise 和 Promise 库感兴趣,您可能会发现这很有用:
Are there still reasons to use promise libraries like Q or BlueBird now that we have ES6 promises?