web-dev-qa-db-fra.com

Existe-t-il une version de setTimeout qui renvoie une promesse ES6?

Semblable à cette question , mais plutôt que de demander comment fonctionnent les promesses en général, je veux spécifiquement savoir:

Quelle est la manière standard/meilleure d'enrouler setTimeout dans quelque chose qui retourne Promise ? Je pense à quelque chose comme Angular $timeout fonction , mais pas Angular spécifique.

35
Michael Kropat

Dans les navigateurs

Tout d'abord non - il n'y a pas de système intégré pour cela. Beaucoup de bibliothèques qui améliorent les promesses ES2015 comme le fouet Bluebird avec elle.

Je pense que l'autre réponse confond l'exécution de la fonction et un retard, cela crée également des délais d'attente impossibles à annuler. Je l'écrirais simplement comme:

function delay(ms){
    var ctr, rej, p = new Promise(function (resolve, reject) {
        ctr = setTimeout(resolve, ms);
        rej = reject;
    });
    p.cancel = function(){ clearTimeout(ctr); rej(Error("Cancelled"))};
    return p; 
}

Ensuite, vous pouvez faire:

delay(1000).then(/* ... do whatever */);

Ou

 doSomething().then(function(){ return delay(1000); }).then(doSomethingElse);

Si nous voulons seulement la fonctionnalité de base dans ES2015, c'est encore plus simple comme:

let delay = ms => new Promise(r => setTimeout(r, ms));

Dans le nœud

Vous pouvez utiliser util.promisify sur setTimeout pour récupérer une fonction delay - ce qui signifie que vous n'avez pas besoin d'utiliser la fonction new Promise constructeur plus.

48
Benjamin Gruenbaum

Voici comment je le mettrais en œuvre:

function delay(duration, func) {
  var args = Array.prototype.slice.call(arguments, 2);

  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(func.apply(null, args));
    }, duration);
  });
}

(Syntaxe ES5 choisie intentionnellement)

Mais il y a peut-être une bibliothèque commune qui le fait déjà, ou une meilleure façon de le faire.

4
Michael Kropat

Si vous avez besoin de l'annulation correcte du délai d'attente promis similaire à clearTimeout - renvoyer la promesse directement à partir de setTimeout n'est pas pratique . Surtout lors de l'utilisation avec ES7 async/wait dans le bloc try...finally. Il est préférable d'avoir une variable distincte pour la manipulation du timeout. J'ai implémenté cette approche en tant que petit paquet wait-timeout . Cela fonctionne comme suit:

import Timeout from 'await-timeout';

async function foo() {
  const timeout = new Timeout();
  try {
    const fetchPromise = fetch('https://example.com');
    const timerPromise = timeout.set(1000).then(() => console.log('Timeout!'));
    await Promise.race([fetchPromise, timerPromise]);
  } finally {
    timeout.clear();
  }
}

Dans cet exemple, le délai d'attente sera définitivement effacé en cas de succès de l'extraction ou de toute erreur et console.log('Timeout!') ne sera pas appelé.

1
vitalets