Supposons que j'utilise le code suivant pour exécuter plusieurs promesses en série:
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return mySpecialFunction(item);
})
}, Promise.resolve())
Le code appelle simplement mySpecialFunction (qui renvoie une promesse), attend que la promesse soit résolue puis appelle à nouveau mySpecialFunction, etc. Ainsi, la fonction est appelée une fois pour chaque élément du tableau, dans le bon ordre.
Comment puis-je m'assurer qu'il y a un délai d'au moins 50 millisecondes entre chaque appel de mySpecialFunction(item)
?
Il est important que les promesses soient exécutées dans le bon ordre et que le temps d'exécution de mySpecialFunction
varie à chaque fois.
J'imagine qu'un sommeil synchrone fonctionnerait, mais je ne prévois pas d'exécuter ce code dans un autre thread, ce qui provoquerait un blocage de l'interface utilisateur gênante dans le navigateur.
Je ne sais pas si setTimer pourrait être utilisé pour cela. Je veux dire que je ne peux pas retarder le retour d'une promesse.
Les réponses sont bonnes, mais elles attendent trop longtemps puisque toutes les réponses attendent peu importe ou que l'opération réelle prenne déjà plus de 50 ms.
Vous pouvez utiliser Promise.all
pour cela.
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return Promise.all([delay(50), mySpecialFunction(item)]);
})
}, Promise.resolve())
Une fonction utilitaire très pratique à utiliser est quelque chose que j'appelle delay()
:
function delay(t, val) {
return new Promise(function(resolve) {
if (t <= 0) {
resolve(val);
} else {
setTimeout(resolve.bind(null, val), t);
}
});
}
Ensuite, vous pouvez l’utiliser dans une chaîne de promesse comme celle-ci:
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item, index) {
return promise.then(function(result) {
// no delay on first iteration
var delayT = index ? 50 : 0;
return delay(delayT, item).then(mySpecialFunction);
})
}, Promise.resolve());
Vous pouvez aussi créer une petite fonction d’utilité pour effectuer l’itération séquentielle avec un délai optionnel:
// delayT is optional (defaults to 0)
function iterateSerialAsync(array, delayT, fn) {
if (!fn) {
fn = delayT;
delayT = 0;
}
array.reduce(function(p, item, index) {
return p.then(function() {
// no delay on first iteration
if (index === 0) delayT = 0;
return delay(delayT, item).then(fn)
});
}, Promise.resolve());
}
Et vous l'utiliseriez comme ceci:
iterateSerialAsync(paramerterArr, 50, mySpecialFunction).then(function(finalVal) {
// all done here
});
Pour obtenir un délai de au moins 50 ms, utilisez Promise.all
:
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
parameterArr.reduce(function(promise, item) {
return promise.then(function() {
return Promise.all([
mySpecialFunction(item),
delay(50)
]);
});
}, Promise.resolve());
Ici vous allez: https://jsbin.com/suvasox/edit?html,js,console
let paramerterArr = ['a','b','c','d','e','f']
paramerterArr.reduce((p, val) => {
return p.then(() => {
return new Promise((res) => {
setTimeout(() => { res(mySpecialFunction(val)); }, 1000);
});
});
}, Promise.resolve());
p doit être le résultat de p.then (). Seulement de cette façon, vous enchaînez les promesses.
Remarquez, je l'ai changé en délai de 1000 ms juste pour mettre l'accent.
Vous trouverez ci-dessous un exemple de réalisation d'une promesse qui ne bloque pas mais attend pendant une période donnée:
function timedPromise(ms, payload) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(payload);
}, ms);
})
}
var time = Date.now();
timedPromise(1000)
.then(function() {
console.log(time - Date.now());
return timedPromise(2000);
}).then(function() {
console.log(time - Date.now());
return timedPromise(3000);
});
Donc, selon ce que vous voulez, vous devriez pouvoir faire quelque chose comme ceci:
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return mySpecialFunction(item);
}).then(function(specialResult) {
return timedPromise(50, specialResult);
});
}, Promise.resolve())
puisque cela semble être une exigence de mySpecialFunction
, je le mettrais en œuvre ici. Pour que la fonction se retarde si elle est appelée moins de 50 ms après le dernier appel
const delayBetweenCalls = (delay, fn) => {
let lastCall = NaN;
return function(/*...arguments*/){
//this and arguments are both forwarded to fn
return new Promise(resolve => {
let poll = () => {
let delta = Date.now() - lastCall;
if(delta < delay){
setTimeout(poll, delta - delay);
}else{
lastCall = Date.now();
resolve( fn.apply(this, arguments) );
}
}
poll();
})
}
}
puis:
const mySpecialFunction = delayBetweenCalls(50, function(some, ...args){
return someValueOrPromise;
});
//and your loop stays the same:
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return mySpecialFunction(item);
})
}, Promise.resolve())
donc peu importe où/comment mySpecialFunction
est appelé, il y aura toujours un délai d'au moins 50 ms avant que le code ne soit exécuté à l'intérieur du rappel transmis.