80

node.jsイベントループの理解に従って、node.jsはシングルスレッドモデルをサポートします。つまり、node.jsサーバーに複数のリクエストを行うと、リクエストごとに新しいスレッドが生成されるのではなく、各リクエストが1つずつ実行されます。これは、node.jsコードの最初のリクエストに対して次のことを行い、その間に新しいリクエストがノードに着信した場合、2番目のリクエストは最初のリクエストが完了するまで5秒のスリープ時間を含めて待機する必要があることを意味します。右?

var sleep = require('sleep');
    sleep.sleep(5)//sleep for 5 seconds

node.jsがリクエストごとに新しいスレッドを生成して、2番目のリクエストが最初のリクエストの完了を待つ必要がないようにする方法はありますか?または特定のスレッドでのみsleepを呼び出すことができますか?

4

4 に答える 4

169

npmモジュールsleepを参照している場合は、readmeにsleep実行をブロックすることが記載されています。だからあなたは正しいです-それはあなたが望むものではありません。代わりに、非ブロッキングであるsetTimeoutを使用する必要があります。次に例を示します。

setTimeout(function() {
  console.log('hello world!');
}, 5000);

es7 async / awaitを使用してこれを実行しようとしている人にとって、この例は次のように役立ちます。

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

const example = async () => {
  console.log('About to snooze without halting the event loop...');
  await snooze(1000);
  console.log('done!');
};

example();
于 2012-11-19T06:01:23.317 に答える
1

それぞれに非同期リクエストがあるループがあり、各リクエストの間に特定の時間を必要とする場合は、次のコードを使用できます。

   var startTimeout = function(timeout, i){
        setTimeout(function() {
            myAsyncFunc(i).then(function(data){
                console.log(data);
            })
        }, timeout);
   }

   var myFunc = function(){
        timeout = 0;
        i = 0;
        while(i < 10){
            // By calling a function, the i-value is going to be 1.. 10 and not always 10
            startTimeout(timeout, i);
            // Increase timeout by 1 sec after each call
            timeout += 1000;
            i++;
        }
    }

この例では、各リクエストの1秒後に、次のリクエストを送信します。

于 2017-04-28T15:45:36.300 に答える
1

deasyncモジュールを検討してください。個人的には、すべての関数を非同期にするPromiseの方法は好きではなく、キーワードasync/awaitがあります。そして、公式のnode.jsはイベントループAPIを公開することを検討する必要があると思います。これにより、コールバックの地獄が簡単に解決されます。Node.jsは、言語ではなくフレームワークです。

var node = require("deasync");
node.loop = node.runLoopOnce;

var done = 0;
// async call here
db.query("select * from ticket", (error, results, fields)=>{
    done = 1;
});

while (!done)
    node.loop();

// Now, here you go
于 2018-05-13T08:34:09.600 に答える
0

Cloud firestoreなどのサードパーティライブラリによって提供される非同期関数または監視対象を操作するwaitFor場合、プロセスを待つ必要があるときに、以下に示すメソッド(TypeScriptですが、アイデアが得られます...)が役立つ関数を見つけました。完了する必要がありますが、コールバック内のコールバック内にコールバックを埋め込む必要はなく、無限ループのリスクもありません。

このメソッドはwhile (!condition)スリープループに似ていますが、非同期で生成され、trueまたはタイムアウトになるまで定期的に完了条件のテストを実行します。

export const sleep = (ms: number) => {
    return new Promise(resolve => setTimeout(resolve, ms))
}
/**
 * Wait until the condition tested in a function returns true, or until 
 * a timeout is exceeded.
 * @param interval The frenequency with which the boolean function contained in condition is called.
 * @param timeout  The maximum time to allow for booleanFunction to return true
 * @param booleanFunction:  A completion function to evaluate after each interval. waitFor will return true as soon as the completion function returns true.   
 */
export const waitFor = async function (interval: number, timeout: number,
    booleanFunction: Function): Promise<boolean> {
    let elapsed = 1;
    if (booleanFunction()) return true;
    while (elapsed < timeout) {
        elapsed += interval;
        await sleep(interval);
        if (booleanFunction()) {
            return true;
        }
    }
    return false;
}

他のタスクを実行する前に、バックエンドで長時間実行されているプロセスを完了したいとします。たとえば、アカウントのリストを合計する関数があるが、計算する前にバックエンドからアカウントを更新したい場合は、次のようにすることができます。

async recalcAccountTotals() : number {
     this.accountService.refresh();   //start the async process.
     if (this.accounts.dirty) {
           let updateResult = await waitFor(100,2000,()=> {return !(this.accounts.dirty)})
     }
 if(!updateResult) { 
      console.error("Account refresh timed out, recalc aborted");
      return NaN;
    }
 return ... //calculate the account total. 
}
于 2020-05-26T18:40:01.343 に答える