Node.js(JavaScript)で待機するにはどうすればよいですか?


385

個人的なニーズに合わせて、スクリプトのようなコンソールを開発しています。長時間停止できるようにする必要がありますが、私の調査によると、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はこれを認識しません。

どうすればこの拡張ポーズを達成できますか?


3
これらの人の1人を正しい答えとしてマークする方法について:)
Billybonks '10年

1
@クリストファー・アレン、関係ないかもしれませんが、仕事をします: require("child_process").execSync('php -r "sleep($argv[1]);" ' + seconds);
ハイサム・スワイレム

ノードスリープトリックを行う可能性がありますNPMモジュール(ただし、私は唯一、デバッグのためにそれを使用します)
ジュリアンソロ

回答:


211

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

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のソリューションに似ていますが、よりすっきりとして拡張が容易です。


7
@LucasSeverynあなたはそれから何か間違ったことをしています。これはコアデザインパターンです。
Elliot Bonneville 2015年

そして、関数の開始が1つの関数だけではなく、非同期化する必要があるコードから10ファイル離れている場合はどうしますか?
Cyril Duchon-Doris

10
@ CyrilDuchon-Dorisなに?
AturSams 2017年

3
@machineghostの回答を使用して、カスタムコードを必要とせず、待機/非同期をサポートするエレガントなプロミスベースのソリューション
Dane Macaulay

これは非同期です。つまり、function1が3秒前に終了すると、それらは互いにオーバーラップし始めます。その後、戻ることもできず、ほとんど利用できません。私がこれまでに見つかった唯一の方法は、使用していたdebugger;
クリスティアントレイニャ

427

古い質問に対する新しい答え。今日(2017年1月2019 6月)ははるかに簡単です。新しい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を使用する必要があります。

2019年6月の更新: NodeJSの最新バージョンを使用することで、そのまま使用できます。コマンドライン引数を提供する必要はありません。Google Chromeでさえ今日サポートしています。

2020年5月の更新:await非同期関数の外で構文 を使用できるようになります。この例のようにトップレベルで

await sleep(1000)
function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
} 

提案はステージ3にあります。今日は、webpack 5(alpha)を使用して使用できます。

より詳しい情報:

  • Nodejsの調和フラグ:https ://nodejs.org/en/docs/es6/
  • ダウンロード用のすべてのNodeJSバージョン:https ://nodejs.org/en/download/releases/

5
await前のキーワードを忘れたと思いますsleep(1000)
Ryan Jarvis

6
これが本当に答えになるはずです。sleepnode.jsパッケージは面倒な場合があります。
Stuart Allen

4
確かに最高のソリューション
Kostas Siabanis

40
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms));:)私のようなonelinerフリークのために
プレドラグStojadinović

21
let sleep = require('util').promisify(setTimeout);ノード7.6以降で動作し、読みやすさを向上
BrianHVB

216

依存関係のない最短のソリューション:

await new Promise(resolve => setTimeout(resolve, 5000));

14
「洗練の高さはシンプルさです。」-クレアブースルース。これは断然最良の答えです、IMO。
アーノルド2018年

3
これは明らかに他の回答よりもはるかに新しいものですが、コードに他の影響を与えることなく、1行で作業を完了する2018年の時点で最もエレガントです。
ヘリック

1
これはいいです。ただし、NodeJS 7.6.0以降を使用する必要があります。古いバージョンでは動作しません。
Ryan Shillington

5
let sleep = require('util').promisify(setTimeout);3文字長いが再利用可能で読みやすい
imo

2
eslintの苦情を回避するには、のresolve代わりに呼び出しますdone。すなわちawait new Promise(resolve => setTimeout(resolve, 5000))
ダレン・クック

150

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

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

2
これはひどく厄介で、一般に悪い習慣です。特に、OPがプログラムの残りの部分をその遅延後に実行したい場合はなおさらです。私の答えを見てください。
エリオットボンネビル2013年

32
@ElliotBonnevilleこれは、概念を説明するための単なる例です。他の場所と同じように、インラインコードを使用する代わりに、コードを因数分解して関数呼び出しにすることができます(推奨)。
JohnnyHK 2013年

@ChristopherKemp:Node.jsにはこのためのソリューションがと呼ばれることがわかりましたnode-fibers見てみな。
Elliot Bonneville 2013年

これは優れたソリューションです。特に、コードを実行したくない場合は、ループ内の「スリープ」メソッドを模倣したいだけです。この例に問題はありません。
2016年

これはクライアントからのリクエストを遅らせるのに最適です。このアプローチを使用して、クライアント側で読み込みスピナーをテストしました
moein rahimi

145

これは単純なブロッキング手法です。

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

それはだ、ブロッキング(コールバックのような)他に何もあなたのスクリプトで起こりませんよう限り。しかし、これはコンソールスクリプトなので、おそらくそれが必要です。


27
恐ろしいかどうかにかかわらず、それは単純なことを行い、waitブロックし、いくつかのテスト目的で機能します。まさに私が探していたもの。
Clijsters

8
サードパーティのライブラリなしで完全に質問に答え、シンプルです。しかし、人々はこれはところでなどこれと非常によく似て重いCPU負荷をシミュレートするための偉大な例です....「恐ろしい」と言うphpied.com/sleep-in-javascript
ドン・チードル

2
また、これは、イベントループを遅くし、他のユーザー/接続も遅くする何かをシミュレートしようとしている場合に必要なアプローチです。遅延したコールバックを追加しても、他のユーザーや接続には影響しません。
Don Cheadle 2017

13
これはspin-waitです。
Mike Atlas

7
目標のようだ@アリ。
フェリックス・ガニオン-グルニエ

63

ノード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で機能する非同期スリープが必要でした。スリープパッケージを試しましたが、Windowsボックスにインストールされません。私は結局使用しました:

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

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

npm install system-sleep

あなたのコードでは、

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

魅力のように機能します。


1
すばらしい回答のおかげで-いくつかの不可能なコードが可能になりました-これはスピンウェイトではありません
danday74

1
さらなる研究では、このモジュールは別の非同期githubリポジトリから分岐された非同期に依存しています。元のリポジトリはハックであるため使用しないよう警告しています。これは機能しますが、すべてのプラットフォームで動作するわけではないため、クロスプラットフォームソリューションが必要な場合は、これを避けてください。
danday74 2017

1
はい、私はそれについての経験を経験したことがなく、開発者にとって素晴らしいです-フードの下では、広く利用可能なCまたはC ++に依存していると思いますが、一部のマシンではそうではなく、それが失敗すると問題が発生するのです-失敗した場合、システムスリープはスピン待機にフォールバックし、コードの実行がフリーズします
danday74

1
このパッケージはMac OSでは機能しないため、相互互換性がないため、機能しません。github.com/jochemstoel/nodejs-system-sleep/issues/4
nuzzoliloを

1
@Nuzzoliloそれは奇妙です。Mac OSには1人の開発者がおり、彼は何も悪いことを言ったことはありません。特定のMac OSバージョンだと思います。スリープは基本的に新しいバージョンのNodeJSに組み込まれているため、この回答も更新しました。
Ryan Shillington

62

最新の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ので、これは本当に問題ではありません。今日のすべての最新のブラウザーがそれをサポートしています。

sleep慣れていない関数async/awaitや太い矢印の演算子について少し洞察を与えると、次のように記述できます。

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

ただし、Fat Arrow演算子を使用すると、さらに小さくなります(よりエレガントになります)。


1
なしでスリープ関数を記述し、asyncその他すべてを同じままにすることもできます。asyncしかし、おそらくそれはより明確です。
ケビン・ペーニャ

良いキャッチ、@KevinPeña。事実、私はそれなしでそれを好むと思いますasync。あなたの提案で私の答えを編集しました。コードが明確になるとは思いません。そのため、代わりにJSDocを使用します。
Lucio Paiva

8
私は私のスクリプトの中で、次のワンライナーを持っているように:const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
korya


34

この質問はかなり古いですが、最近V8には、OPが要求したものを実行できるジェネレーターが追加されました。ジェネレーターは、一般的に、suspendgen-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');
})();

関連する読書(恥知らずな自己宣伝による):ジェネレーターの大したことは何ですか?


2
良い答え-読むべきですyield setTimeout(suspend.resume(), 10000);
edhubbell

1
ありがとう、@ edhubbell。この回答は非常に古いバージョンのサスペンドに基づいていましたが、最新のものは正しいです。答えを更新します。
jmar777 2015

これはどのバージョンのノードですか?
danday74

1
@ danday74フラグが設定されていなかった時期を正確に思い出すことはできませんが、v0.12以降は--harmonyフラグの後ろにあり、node.greenによると、少なくともv4.8.4以降はフラグなしで使用できます。node.green/#ES2015-functions-generators-basic-functionality。ただし、新しいasync/await構文を使用すると、これより優れたソリューションが提供され、などの追加のライブラリは必要ありませんsuspend。例については、この回答を参照してください:stackoverflow.com/a/41957152/376789。非同期関数はv7.10以降で使用できます(フラグなし)。
jmar777 2017

20

Linux / nodejsでは、これは私にとってはうまくいきます:

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

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

これはブロッキングですが、ビジーな待機ループではありません。

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


sleepUNIXの初期の頃のen.wikipedia.org/wiki/Sleep_%28Unix%29から、ほとんどどこにでもあり、実用的な方法です。存在しない可能性のある「まれではない」OSはWindowsだけです(ただし、そこに挑戦することはできますchild_process.spawnSync('timeout', ['/T', '10'])
人類

17

「ゴルフをコード化」したい場合は、ここで他のいくつかの回答の短いバージョンを作成できます。

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

実際、util.promisifyを使用すると、コールバックを提供せずにスリープを呼び出すことはできません。 nodejs.org/api/...
ハウィー

1
がありませんawait。それは一種のコールバックを作成し、物事を一時停止し、そのコールバックが戻ったときにコードを再開します。コールバックは値を返しますが、この場合は気にしませんので、の左側には何もありませんawait
machineghost 2017

1
それを1行に記述してコードGolfをワイン化します;)const sleep = require( 'util')。promisify(setTimeout);
Fabian

14

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

https://github.com/luciotato/waitfor

wait.forを使用すると、ノードのイベントループをブロックせずに、標準のnodejs非同期関数を、それが同期関数であるかのように呼び出すことができます。

必要に応じて順次コーディングすることができます。つまり、個人的な使用のためにスクリプトを簡略化するのに最適です(私は推測しています)。

コードを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. 

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


TypeError: Object #<Object> has no method 'miliseconds'
CaffeineAddiction 14年

コメントは言う: "// defined in waitfor / paralell-tests.js"そのファイルからそれを取得します。
Lucio M. Tato 2014年

2
それを取得した後wait.for/paralell-tests.js、未定義のプロパティなどに関連する別のエラーが発生したので、それらもコピーする必要がありました。必要のない方法でコードを整理してみませんか?
user907860 14年

Wait.forおよびその他のファイバーソリューションは、まったく新しい世界を切り開いてくれました。可能であれば、これを100万回投票します。ほとんどのnodejsコミュニティはファイバーに反対していますが、それらは素晴らしい追加機能であり、コールバック地獄に関しては間違いなくその位置を占めていると思います。
Levi Roberts

7

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

Node.jsが続きます

process.nextTick()

代わりに後でコードを実行するにはsetTimeout()を使用します。例えば、

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

2

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関数はresolve内のコールバックになることに注意してくださいnew Promise(...)

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

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


1
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非同期呼び出しからデータを抽出し、解決されたデータをジェネレーターに戻すメカニズムが提供されました。事実上、非同期呼び出しを同期化します。


このコードは質問に答えることがありますが、問題を解決する方法や理由に関する追加のコンテキストを提供すると、回答の長期的な価値が向上します。
ドナルドダック

@DonaldDuckに感謝します。私の回答のコードは、おそらくJavaScriptの改善の最もエキサイティングな部分です。私は何人かの超賢い人々がコールバック地獄問題を解決するためにこの方法を考えるのにとても驚いています。
Qian Chen


0

テスト目的で一時停止するだけの場合は、現在のスレッドの実行を試してください。

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

単純に、あるイベントが発生する(コード内のどこかでdone変数がtrueに設定されていることで示される)か、タイムアウトの期限が切れると、100ミリ秒ごとにチェックするまで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

一部の人々のために、受け入れられた答えが機能していません、私はこの他の答えを見つけました、そしてそれは私のために働いています:setTimeout()コールバックにパラメーターを渡すにはどうすればよいですか?

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

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


0

これらすべてのsetTimeout、sleepなどの多くのことを行う代わりに、使用することをお勧めします

const delay = require('delay');
await delay(2000); // will wait for 2 seconds before executing next line of code

「遅延」とは何かを説明し、そのドキュメントにリンクできますか?なぜそれが良いのですか?
ボイシー

-2

他の答えは素晴らしいですが、私は別のタクトを取ると思いました。

あなたが本当に探しているのがLinuxの特定のファイルを遅くすることだけなら:

 rm slowfile; mkfifo slowfile; perl -e 'select STDOUT; $| = 1; while(<>) {print $_; sleep(1) if (($ii++ % 5) == 0); }' myfile > slowfile  &

ノードmyprogスローファイル

これは5行ごとに1秒スリープします。ノードプログラムはライターと同じくらい遅くなります。他のことをしている場合は、通常の速度で続行されます。

mkfifoは、先入れ先出しのパイプを作成します。これがこの作業を行うものです。perl行は、必要なだけ速く書き込みます。$ | = 1は、出力をバッファリングしないことを示しています。


-3

この質問の回答を読んだ後、必要に応じてコールバックも実行できる簡単な関数をまとめました。

function waitFor(ms, cb) {
  var waitTill = new Date(new Date().getTime() + ms);
  while(waitTill > new Date()){};
  if (cb) {
    cb()
  } else {
   return true
  }
}

-4

詳細については

yield sleep(2000); 

Redux-Sagaを確認してください。ただし、これはモデルフレームワークとしてReduxを選択した場合に固有です(厳密には必要ありません)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.