web-dev-qa-db-ja.com

Node.js(Javascript)でしばらく待つことができますか

私は個人的なニーズのためのスクリプトのようなコンソールを開発しています。私は長時間休止できるようにする必要があります、しかし、私の調査から、node.jsは必要に応じて止める方法がありません。しばらくすると、ユーザーの情報を読みにくくなります。コードが表示されていますが、次のように機能するには他のコードを内部に配置する必要があると考えています。

setTimeout(function() {
}, 3000);

しかし、このコード行の後に、一定期間後に実行するすべてのものが必要です。

例えば、

//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. 

こんなものも見ました

yield sleep(2000);

しかし、node.jsはこれを認識しません。

どうすればこの一時停止を延長できますか?

249

これを行う最善の方法は、コードを次のように複数の関数に分割することです。

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);

これは JohnnyHK のソリューションに似ていますが、はるかに洗練されていて拡張が簡単です。

162

古い質問に対する新しい答えです。今日(2017年1月)、それはずっと簡単です。 new async/await構文 を使用できます。例えば:

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

インストールやプラグインをせずにasync/awaitをそのまま使用するには、--harmonyフラグを使用してnode-v7またはnode-v8を使用する必要があります。

詳細情報:

223

遅延後に実行したいコードをsetTimeoutコールバック内に置きます。

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

これは簡単なブロックテクニックです。

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

スクリプトで他に何も起こらない限り(コールバックのように)、 ブロッキング /です。しかし、これはコンソールスクリプトなので、多分それはあなたが必要としているものです!

110
atlex2

現代のJavascriptを使ったシンプルでエレガントな睡眠機能

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

依存関係もコールバック地獄もありません。それでおしまい :-)


質問で与えられた例を考えると、これは2つのコンソールログの間でどのようにスリープするかです:

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

main();

「欠点」は、あなたのメイン関数がasyncでなければならないことです。しかし、あなたがすでに現代のJavascriptコードを書いていることを考えると、あなたはおそらく(あるいは少なくともそうすべきです!)あなたのコード全体にasync/awaitを使っているので、これは実際問題ではありません。今日のすべての最近のブラウザは サポート それです。

async/awaitと太い矢印の演算子に慣れていない人のためにsleep関数について少し洞察を与えて、これはそれを書くための冗長な方法です:

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

太い矢印演算子を使用すると、さらに小さくなります(そしてよりエレガントになります)。

49
Lucio Paiva

あなたはこれを使用することができます www.npmjs.com/package/sleep

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

依存関係のない最短の解決策:

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

ノード7.6.0以上

ノードは待機をネイティブにサポートします。

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

あなたは非同期関数を使用することができれば:

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

または

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

古いバージョンのノードで(元の回答)

私は、長いwhileループでCPUを占有することなく、WindowsとLinuxで動作する非同期スリープを望みました。私はsleepパッケージを試しましたが、Windowsボックスにはインストールされませんでした。私は使用してしまいました:

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

インストールするには、次のように入力します。

npm install system-sleep

あなたのコードでは、

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

魅力のように働きます。

34

この質問はかなり古いですが、最近V8は、OPが要求したことを達成できるジェネレータを追加しました。ジェネレータは一般的に suspend または gen-run のようなライブラリの助けを借りた非同期インタラクションに最も使いやすいです。

これはsuspendを使った例です:

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

関連読書(恥知らずな自己宣伝として): 発電機との大したことは何ですか?

34
jmar777

Linux/nodejsではこれは私のために働く:

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

var sleep = spawnSync( 'sleep'、[1.5]);

ブロックしていますが、ビジーな待機ループではありません。

指定する時間は秒単位ですが、少しでもかまいません。他のOSにも同様のコマンドがあるかどうかわかりません。

16
Bart Verheijen

私は最近、同期モードで非同期関数を呼び出すために wait.for と呼ばれるより単純な抽象化を作成しました(ノードファイバーに基づく)。今後のES6ジェネレーターに基づくバージョンもあります。

https://github.com/luciotato/waitfor

wait.for を使用すると、標準のnodejs async関数を、あたかもsync関数であるかのように、ノードのイベントループをブロックすることなく呼び出すことができます。

必要に応じて順番にコーディングすることができます。つまり、個人的な使用のためにスクリプトを単純化するのに最適です。

wait.for を使用すると、コードは次のようになります。

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. 

任意の非同期関数もSyncモードで呼び出すことができます。例を確認してください。

13
Lucio M. Tato

あなたが「コードゴルフ」をしたいならば、あなたはここで他の答えのいくつかのより短いバージョンを作ることができます:

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

しかし、私の意見では本当に理想的な答えは、Nodeのutilライブラリとそのpromisify関数を使用することです。

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

どちらの場合も、awaitを使用してsleep関数を呼び出すだけで一時停止できます。

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

Javascriptエンジン(v8)はイベントキュー内のイベントのシーケンスに基づいてコードを実行するので、javascriptが指定された時間の後に正確に実行をトリガーすることは厳密ではありません。つまり、後でコードを実行するように数秒を設定した場合、トリガーコードは純粋にイベントキュー内のシーケンスに基づいています。そのため、コードの実行をトリガーするのに指定された時間以上かかることがあります。

それでNode.jsが続きます、

process.nextTick()

後でコードを実行する場合はsetTimeout()を使用してください。例えば、

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

ES6はPromiseをサポートしているので、サードパーティの支援なしでそれらを使用できます。

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.

それからこのようにそれを使ってください:

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

doWhat関数はnew Promise(...)内でresolveコールバックになることに注意してください。

また、これは非同期睡眠です。イベントループをブロックしません。睡眠を遮断する必要がある場合は、C++バインディングを使用して睡眠の遮断を実現するこのライブラリを使用してください。 (非同期環境のようにNodeでスリープをブロックする必要性はまれですが)

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

2
treecoder

これは @ atlex2によって提案されたダーティブロッキングアプローチ に基づくmoment.js風味のモジュールです。 テストにのみ使用してください

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');
});

上記のこのコードは、Javascriptの非同期コールバックヘル問題を解決したことによる副作用です。これが私がJavascriptをバックエンドの便利な言語にする理由でもあります。実際、これは私の意見では現代のJavaScriptに導入された最もエキサイティングな改善です。それがどのように機能するかを完全に理解するためには、ジェネレータがどのように機能するかについて十分に理解する必要があります。 functionキーワードとそれに続く*は、現代のJavascriptではジェネレータ関数と呼ばれています。 npmパッケージcoはジェネレータを実行するためのランナー関数を提供しました。

本質的にジェネレーター関数はyieldキーワードを持つ関数の実行を一時停止する方法を提供しました、同時にジェネレーター関数のyieldはジェネレーターの内側と呼び出し側の間で情報を交換することを可能にしました。これにより、呼び出し側が非同期呼び出しからpromiseからデータを抽出し、解決されたデータをジェネレータに返すメカニズムが提供されました。事実上、非同期呼び出しを同期化します。

1
Elgs Qian Chen

簡単なのは、何らかのイベントが発生するまで(コード内の別の場所でdone変数がtrueに設定されていることで示される)、または100msごとにタイムアウトがタイムアウトするまで5秒間待つことです。

    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

何人かの人々にとって、受け入れられた答えはうまくいかなかった、私はこの他の答えを見つけて、それは私のために働いています: どうやったらsetTimeout()コールバックにパラメータを渡せますか?

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

'hello'は渡されるパラメータです。タイムアウト時間の経過後にすべてのパラメータを渡すことができます。答えをくれた@Fabio Phmsに感謝します。

0
Dazt

Readline-sync( https://www.npmjs.com/package/readline-sync )をご覧ください。

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);
  }
}

たぶんベストプラクティスではないが、私のために仕事をする

0
MonoThreaded

テスト目的で中断するだけの場合は、現在のスレッド実行でこれを試してください。

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