web-dev-qa-db-fra.com

Comment puis-je attendre dans Node.js (Javascript), je dois faire une pause pendant un certain temps

Je développe une console comme un script pour des besoins personnels. Je dois pouvoir faire une pause prolongée, mais d'après mes recherches, node.js n'a aucun moyen de s'arrêter si nécessaire. Il est de plus en plus difficile de lire les informations des utilisateurs après un certain temps. J’ai vu du code, mais je pense qu’il doit contenir un autre code pour qu’il fonctionne, par exemple:

setTimeout(function() {
}, 3000);

Cependant, j'ai besoin de tout ce qui suit cette ligne de code pour s'exécuter après la période.

Par exemple, 

//start-of-code
console.log('Welcome to My Console,');
some-wait-code-here-for-ten-seconds..........
console.log('Blah blah blah blah extra-blah');
//endcode. 

J'ai aussi vu des choses comme

yield sleep(2000);

Mais node.js ne reconnaît pas cela.

Comment puis-je obtenir cette pause prolongée?

221
Christopher Allen

La meilleure façon de faire est de diviser votre code en plusieurs fonctions, comme ceci:

function function1() {
    // stuff you want to happen right away
    console.log('Welcome to My Console,');
}

function function2() {
    // all the stuff you want to happen after that pause
    console.log('Blah blah blah blah extra-blah');
}

// call the first chunk of code right away
function1();

// call the rest of the code and have it execute after 3 seconds
setTimeout(function2, 3000);

C'est similaire à la solution de JohnnyHK , mais beaucoup plus nette et plus facile à étendre.

147
Elliot Bonneville

Une nouvelle réponse à une vieille question. Aujourd'hui (janvier 2017), c'est beaucoup plus facile. Vous pouvez utiliser la syntaxe new async/await . Par exemple:

async function init(){
   console.log(1)
   await sleep(1000)
   console.log(2)
}
function sleep(ms){
    return new Promise(resolve=>{
        setTimeout(resolve,ms)
    })
}

Pour utiliser async/await prêt à l'emploi, sans installation ni plug-in, vous devez utiliser node-v7 ou node-v8, à l'aide de l'indicateur --harmony.

Plus d'informations:

186

Placez le code que vous voulez exécuter après le délai dans le rappel setTimeout:

console.log('Welcome to My Console,');
setTimeout(function() {
    console.log('Blah blah blah blah extra-blah');
}, 3000);
127
JohnnyHK

C'est une technique de blocage simple:

var waitTill = new Date(new Date().getTime() + seconds * 1000);
while(waitTill > new Date()){}

C'est bloquant dans la mesure où rien d'autre ne se passera dans votre script (comme des rappels). Mais puisqu'il s'agit d'un script de console, c'est peut-être ce dont vous avez besoin!

102
atlex2

Vous pouvez utiliser ceci www.npmjs.com/package/sleep

var sleep = require('sleep');
sleep.sleep(10); // sleep for ten seconds
48
Aleksej

Fonction de sommeil simple et élégante utilisant le Javascript moderne

function sleep(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}

Pas de dépendances, pas de rappel enfer; c'est tout :-)


Considérant l'exemple donné dans la question, voici comment nous dormirions entre deux journaux de consoles:

async function main() {
    console.log("Foo");
    await sleep(2000);
    console.log("Bar");
}

main();

L'inconvénient est que votre fonction principale doit maintenant être aussi async. Mais, étant donné que vous écrivez déjà du code Javascript moderne, vous utilisez probablement (ou du moins devriez le faire!) async/await dans tout votre code, ce n'est donc vraiment pas un problème. Tous les navigateurs modernes actuels supportent it.

Donner un peu de perspicacité dans la fonction sleep pour ceux qui ne sont pas habitués aux opérateurs async/await et fat arrow, c’est la façon la plus verbeuse de l’écrire:

function sleep(millis) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () { resolve(); }, millis);
    });
}

L'utilisation de l'opérateur de flèche grasse, cependant, le rend encore plus petit (et plus élégant).

46
Lucio Paiva

La solution la plus courte sans aucune dépendance:

await new Promise(done => setTimeout(done, 5000));
37
k06a

Cette question est assez ancienne, mais récemment, la V8 a ajouté des générateurs pouvant accomplir les tâches demandées par le PO. Les générateurs sont généralement les plus faciles à utiliser pour les interactions asynchrones avec l’aide d’une bibliothèque telle que suspend ou gen-run .

Voici un exemple utilisant susp:

suspend(function* () {
    console.log('Welcome to My Console,');
    yield setTimeout(suspend.resume(), 10000); // 10 seconds pass..
    console.log('Blah blah blah blah extra-blah');
})();

Lecture connexe (par le biais d'une auto-promotion éhontée): Quel est le problème avec les générateurs? .

33
jmar777

Sur le nœud 7.6.0 ou supérieur

Le nœud prend en charge l'attente native:

const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));

alors si vous pouvez utiliser des fonctions asynchrones:

await sleep(10000); // sleep for 10 seconds

ou:

sleep(10000).then(() => {
  // This will execute 10 seconds from now
});

Sur les anciennes versions du noeud (réponse originale)

Je voulais un sommeil asynchrone fonctionnant sous Windows et Linux, sans monopoliser mon processeur avec une longue boucle while. J'ai essayé le paquet de sommeil mais il n'a pas été installé sur ma machine Windows. J'ai fini par utiliser:

https://www.npmjs.com/package/system-sleep

Pour l'installer, tapez:

npm install system-sleep

Dans votre code, 

var sleep = require('system-sleep');
sleep(10*1000); // sleep for 10 seconds

Fonctionne comme un charme.

24
Ryan Shillington

Sur Linux/nodejs cela fonctionne pour moi:

const spawnSync = require ('child_process'). spawnSync;

var sleep = spawnSync ('sommeil', [1.5]);

Il bloque, mais ce n'est pas une boucle d'attente occupée.

Le temps que vous spécifiez est en secondes mais peut être une fraction. Je ne sais pas si d'autres systèmes d'exploitation ont une commande similaire.

14
Bart Verheijen

J'ai récemment créé une abstraction plus simple appelée wait.for pour appeler des fonctions asynchrones en mode sync (basé sur les fibres de nœud). Il existe également une version basée sur les générateurs ES6 à venir.

https://github.com/luciotato/waitfor

En utilisant wait.for, vous pouvez appeler n’importe quelle fonction async de noeud standard, comme s’il s’agissait d’une fonction de synchronisation, sans bloquer la boucle d’événement du noeud. 

Vous pouvez coder de manière séquentielle quand vous en avez besoin, ce qui est (je suppose) parfait pour simplifier vos scripts pour un usage personnel.

en utilisant wait.for, votre code sera:

require('waitfor')

..in a fiber..
//start-of-code
console.log('Welcome to My Console,');
wait.miliseconds(10*1000); //defined in waitfor/paralell-tests.js - DOES NOT BLOCK
console.log('Blah blah blah blah extra-blah');
//endcode. 

De plus, toute fonction asynchrone peut être appelée en mode Sync ..... Vérifiez les exemples.

13
Lucio M. Tato

Si vous voulez "coder le golf", vous pouvez créer une version abrégée de certaines des autres réponses ici:

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

Mais à mon avis, la solution idéale consiste à utiliser la bibliothèque util de Node et sa fonction promisify, conçues pour ce type de choses (créer des versions basées sur des promesses de choses existantes non basées sur des promesses):

const util = require('util');
const sleep = util.promisify(setTimeout);

Dans les deux cas, vous pouvez faire une pause en utilisant simplement await pour appeler votre fonction sleep:

await sleep(1000); // sleep for 1s/1000ms
11
machineghost

Depuis, le moteur javascript (v8) exécute le code en fonction de la séquence d'événements dans la file d'attente d'événements. Il n'est pas strict que javascript déclenche exactement l'exécution à une heure donnée. En d'autres termes, lorsque vous définissez quelques secondes pour exécuter le code ultérieurement, le code de déclenchement est purement basé sur la séquence dans la file d'attente des événements. Donc, le déclenchement de l'exécution du code peut prendre plus que le temps spécifié.

Alors Node.js suit,

process.nextTick()

pour exécuter le code ultérieurement à la place de setTimeout (). Par exemple,

process.nextTick(function(){
    console.log("This will be printed later");
});
6

Avec ES6 prenant en charge Promises, nous pouvons les utiliser sans aucune aide de tiers.

const sleep = (seconds) => {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, (seconds * 1000));
    });
};

// We are not using `reject` anywhere, but it is good to
// stick to standard signature.

Ensuite, utilisez-le comme ceci:

const waitThenDo(howLong, doWhat) => {
    return sleep(howLong).then(doWhat);
};

Notez que la fonction doWhat devient le rappel resolve au sein de la new Promise(...).

Notez également qu'il s'agit d'un sommeil ASYNCHRONE. Il ne bloque pas la boucle d'événement. Si vous avez besoin de bloquer le sommeil, utilisez cette bibliothèque qui réalise le blocage à l'aide de liaisons C++. (Bien que la nécessité d'un sommeil bloquant dans les environnements nodaux comme les environnements asynchrones soit rare.)

https://github.com/erikdubbelboer/node-sleep

2
treecoder

Ceci est un module aromatisé moment.js basé sur la approche de blocage sale proposée par @ atlex2 . Utilisez ceci uniquement pour tester.

const moment = require('moment');

let sleep = (secondsToSleep = 1) => {
    let sleepUntill = moment().add(secondsToSleep, 'seconds');
    while(moment().isBefore(sleepUntill)) { /* block the process */ }
}

module.exports = sleep;
1
Boaz
let co = require('co');
const sleep = ms => new Promise(res => setTimeout(res, ms));

co(function*() {
    console.log('Welcome to My Console,');
    yield sleep(3000);
    console.log('Blah blah blah blah extra-blah');
});

Ce code ci-dessus est l’effet secondaire du problème de l’enfer de rappel asynchrone par Javascript. C’est aussi la raison pour laquelle j'estime que cela fait de Javascript un langage utile dans le backend. En fait, c’est à mon avis l’amélioration la plus excitante introduite dans le Javascript moderne. Pour bien comprendre son fonctionnement, le fonctionnement du générateur doit être parfaitement compris. Le mot clé function suivi d'un * est appelé une fonction génératrice en Javascript moderne. Le package npm co fournissait une fonction d'exécution pour exécuter un générateur.

Essentiellement, la fonction de générateur permettait de suspendre l'exécution d'une fonction avec le mot clé yield et, dans le même temps, yield dans une fonction de générateur, ce qui permettait l'échange d'informations entre le générateur et l'appelant. Cela fournissait un mécanisme permettant à l'appelant d'extraire les données d'une promise d'un appel asynchrone et de renvoyer les données résolues au générateur. Effectivement, il rend un appel asynchrone synchrone.

1
Elgs Qian Chen

simple, nous allons attendre 5 secondes qu'un événement se produise (ce qui serait indiqué par la variable done définie sur true quelque part dans le code) ou à l'expiration du délai imparti que nous vérifierons toutes les 100 ms

    var timeout=5000; //will wait for 5 seconds or untildone
    var scope = this; //bind this to scope variable
    (function() {
        if (timeout<=0 || scope.done) //timeout expired or done
        {
            scope.callback();//some function to call after we are done
        }
        else
        {
            setTimeout(arguments.callee,100) //call itself again until done
            timeout -= 100;
        }
    })();
0
Stan Sokolov

Pour certaines personnes, la réponse acceptée ne fonctionne pas, j'ai trouvé cette autre réponse et elle fonctionne pour moi: Comment puis-je passer un paramètre à un rappel setTimeout ()?

var hello = "Hello World";
setTimeout(alert, 1000, hello); 

'bonjour' est le paramètre passé, vous pouvez passer tous les paramètres après le délai d'attente. Merci à @Fabio Phms pour la réponse.

0
Dazt

Consultez readline-sync ( https://www.npmjs.com/package/readline-sync )

Installer avec npm install readline-sync

var readlineSync = require('readline-sync');
while(true) {
  var input = readlineSync.question("What is your input?");
  if(input === 'exit') {
    process.exit();
  } else {
    console.log("Your input was " + input);
  }
}

Peut-être pas la meilleure pratique mais fait le travail pour moi

0
MonoThreaded

Si vous avez juste besoin de suspendre à des fins de test, votre exécution de thread actuelle essayez ceci:

function longExecFunc(callback, count) {

    for (var j = 0; j < count; j++) {
        for (var i = 1; i < (1 << 30); i++) {
            var q = Math.sqrt(1 << 30);
        }
    }
    callback();
}
longExecFunc(() => { console.log('done!')}, 5); //5, 6 ... whatever. Higher -- longer
0
Ivan Talalaev