我有一个我一直在努力解决的承诺链问题。我打电话给外部api,它返回我需要处理和摄取到mongo数据库的数据。我正在使用nodejs和mongodb。无论如何,对api的调用工作正常,问题是我正在制作大量的api。我想让它们慢下来,比如为一组做出所有的调用。等一下。拨打下一组的所有电话。如果这是已知数量的集合,我会保证链接它们。我不知道有多少套,所以我正在循环它们。我认为关闭是问题,但不能解决它。关于示例代码!
function readApi(carFactory){
var promise = new Promise(function(resolve, reject) {
// call out to api, get set of car data from factory1
console.log(carFactory);
if (true) {
console.log('resolved');
resolve("Stuff worked!"+carFactory);
}
else {
reject(Error("It broke"));
}
});
return promise;
}
function manager(){
//singular call
readApi("this is a singular test").then(returnedThing=>{
console.log(returnedThing); //Stuff worked! this is a singular test
});
let dynamicList = ["carFactory1", "carFactory2","carFactory3","carFactory..N"];
let readApiAction = [];
dynamicList.forEach(carIter=>{
readApiAction.push(readApi(carIter));
});
//ok so now I got an array of promise objects.
//I want to call the first one, wait 1 minute and then call the next one.
//originally I was calling promise.all, but there is no way to get at
//each promise to pause them out so this code is what I am looking to fix
let results= Promise.all(readApiAction);
results.then(data=>{
data.forEach(resolvedData=>{
console.log(resolvedData); //Stuff worked carFactory1, etc...
});
});
//singular call with timeout, this does not work, each one called at the same time
let readApiActionTimeouts = [];
dynamicList.forEach(carIter=>{
setTimeout(callingTimeout(carIter), 6000);
});
}
//just a function to call the promise in a timeout
//this fails with this - TypeError: "callback" argument must be a function
function callingTimeout(carIter){
readApi(carIter).then(returnedThing=>{
console.log("timeout version"+returnedThing);
});
}
答案 0 :(得分:4)
理论上的一点点。原生> $list.tail(5).list.tail
j
只是对承诺进行分组。它们仍然是同时执行的(尽管如同所有JS代码一样以异步方式执行)。这意味着它仍然会拥塞API并执行大量调用。
另外需要注意的是,如果您想延迟承诺,则必须延迟其返回值(例如Promise.all
)。为此,您可以使用setTimeout INSIDE 新承诺(请参阅下面的详细说明)。
设置超时是异步的。它不像其他语言一样工作(它不只是暂停执行)。在代码中设置固定超时只会导致所有执行操作移动6秒。它们仍然是并行发生的(不同的时刻,但是它有一点不同)。尝试例如为循环中的每一个生成不同的超时 - 你会注意到它们发生在不同的时间但是!对于宣传的代码,这不是一个好的解决方案!
现在 - 实际答案的时间!
如果您使用Bluebird,它有一种特殊方法可以为每个承诺添加延迟或超时。没有它,你必须在Promise周围写一个包装器,例如在特定时间后解决它,然后将其与resolve
一起使用。
第一个解决方案(蓝鸟):
Promise.all
然后在你的代码中:
function delayMyPromise(myPromise, myDelay);
return Promise.delay(myDelay).then(function() {
return myPromise;
});
});
甚至更酷,您可以使用Bluebird的return Promise.all(delayMyPromise(promise1, 1000), delayMyPromise(promise2, 2000)); // Notice different delays, you may generate them programatically
而不是具有特殊并发设置的Promise.map
,这样您就可以强制您的承诺按特定顺序执行,例如一次2个。
这就是我在之前项目中的表现:)
更多信息:
纯粹的原生承诺实施:
Promise.all
但是,如果你不介意使用Bluebird,我会强烈推荐第一种方法。就像Promise的function delayMyPromise(myPromise, myDelay) {
return new Promise(function (resolve, reject) {
setTimeout(function() {
return resolve(myPromise);
}, myDelay);
});
}
一样,而且速度非常快:)
答案 1 :(得分:1)
你可以使用递归来做这样的事情。
当您致电.forEach
时,每次迭代都会立即发生。
在下面的示例中,在发生setTimeout之前不会调用doSomething
,这意味着每个字母相隔1秒打印。
let letters = ["a", "b", "c"];
function doSomething(arr) {
console.log(arr[0]);
if (arr.length > 1) {
setTimeout(() => doSomething(arr.slice(1)), 1000);
}
}
doSomething(letters);

或者,对于你的承诺数组:
let promises = [
Promise.resolve("A"),
Promise.resolve("B"),
Promise.resolve("C"),
];
function doSomething(arr) {
arr[0].then((result) => {
console.log(result);
if (arr.length > 1) {
setTimeout(() => doSomething(arr.slice(1)), 1000);
}
})
}
doSomething(promises);

答案 2 :(得分:1)
您收到错误:TypeError: "callback" argument must be a function
因为您的callingTimeout
没有返回任何内容而setTimeout
需要一个函数作为参数,这是如何解决它:
let readApiActionTimeouts = [];
dynamicList.forEach(carIter=>{
callingTimeout(carIter)
});
你的承诺:
function readApi(carFactory){
var promise = new Promise(function(resolve, reject) {
//...
setTimeout(()=>{
resolve("Stuff worked!"+carFactory);
}, 6000);
//...
});
return promise;
}