nodejs事件と事件循環概要


概要
javascriptに詳しい友達はすべて事件を使ったことがあるべきで、例えばマウスの移動、マウスのクリック、キーボードの入力など.私たちはjavascriptの中でこれらの事件を監督して、それによって相応する処理を触発します.
同じnodejsにもイベントがあり、専用のeventsモジュールがあります.
同時にイベントとイベントサイクルもnodejsが非同期IOを構築するための非常に重要な概念である.
今日は詳しく調べてみます.
イベント
nodejsはイベントのために専門的なモジュールを提供しました.lib/events.js.
私達はnodejsを使ってwebサーバーを構築すると言っていましたか?
const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('welcome to www.flydean.com
') })
ここで、各要求は、requestイベントをトリガする.
nodejsのコアAPIは、非同期イベント駆動に基づいてアーキテクチャされているので、nodejsには多くのイベントがある.
例えば、net.Serverは、新しい接続があるたびにイベントをトリガし、fs.ReadStreamはファイルを開いたときにイベントをトリガし、streamはデータ読み取り時にイベントをトリガします.
どうやってnodejsのイベントを構築するかを見ます.
const EventEmitter = require('events')
const eventEmitter = new EventEmitter()
eventsでよく使われる方法は二つあります.それぞれonとemitです.
onはイベントをモニターするために使用され、eitはイベントをトリガするために使用されます.
eventEmitter.on('fire', () => {
  console.log('  ')
})

eventEmitter.emit('fire')
emitはまた、パラメータを持つことができます.次のパラメータの状況を見ます.
eventEmitter.on('fire', who => {
  console.log(`   ${who}`)
})

eventEmitter.emit('fire', '  ')
二つのパラメータの状況を見てください.
eventEmitter.on('fire', (who, when) => {
  console.log(`   ${who} ${when}`)
})

eventEmitter.emit('fire', '   ','now')
デフォルトでは、EventEmitterは登録の順序で同期してすべてのモニターを呼び出す.このようにして、イベントの正確な順序を確保し、競合条件と論理エラーを回避することができる.
非同期実行が必要な場合は、setImmedite()またはprocess.nextTick()を使用して非同期実行モードに切り替えることができる.
eventEmitter.on('fire', (who, when) => {
    setImmediate(() => {
      console.log(`   ${who} ${when}`);
  });
})

eventEmitter.emit('fire', '   ','now')
この他にも、eventsは他のいくつかの方法をサポートしています.
オンス():シングルモニターを追加
removeListener()/off():イベントからイベントモニターを削除する
removeAllListeners():イベントのすべてのモニターを削除します.
イベントサイクル
私たちはnodejsのコードが単スレッド環境で実行されていることを知っています.毎回一つのことだけを処理します.
この処理は、マルチスレッド環境におけるデータ同期の問題を回避し、処理効率を大幅に向上させる.
イベントサイクルとは、プロセッサがプログラム周期でこのサイクルのイベントを処理した後、次のイベント周期に入り、次のイベント周期のイベントを処理するサイクルのことです.
イベントサイクルのブロック
イベント処理中に、あるイベントの処理がブロックされたら、他のイベントの実行に影響を与えます.だから、JSではほとんどのIOはブロックされていません.これもなぜjavascriptにこんなに多くのリプライがあるのですか?
イベントサイクル例
簡単なイベントサイクルの例を見ます.
const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    action2()
    action3()
}

action1()
上のコード出力:
action1
action2
action3
スタックとメッセージキュー
関数間の呼び出しはスタックによって実現されることを知っています.上記の例では、私たちの呼び出し順序もスタックによって実現されます.
しかし、関数内のすべての方法がスタックに入るわけではなく、メッセージキューに入れる方法もあります.
もう一つ例を挙げます.
const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    setTimeout(action2, 0)
    action3()
}

action1()
上のコードの運行結果:
action1
action3
action2
結果は違っています.これはsettimeoutがタイマーをトリガし、タイマーが満了すると、スタックに入れずにメッセージキューに入れられて待機するからです.
イベントサイクルは、スタック内のイベントを優先的に処理し、スタック内にデータがない場合のみ、消費メッセージのキュー内のイベントに移行する.
上記の例ではsetTimeoutのtimeout時間は0ですが、actition 3が実行されるまで待つ必要があります.
なお、setTimeoutにおけるtimeoutは、現在のスレッドで待機しているわけではなく、ブラウザまたは他のJS実行環境によって起動されている.
作業キューとpromise
ES 6のPromiseは、スタックの呼び出しの最後に置くのではなく、作業キューを使用すると、速やかに非同期関数の結果を実行します.
例を挙げます
const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    setTimeout(action2, 0)
    new Promise((resolve, reject) =>
        resolve('   action3  、action2  ')
    ).then(resolve => console.log(resolve))
    action3()
}

action1()
出力結果:
action1
action3
   action3  、action2  
action2
これは、現在の関数が終わる前にresoveのPromiseが現在の関数の後にすぐに実行されるからです.
つまり、まずスタックを実行し、作業キューを実行し、最後にメッセージキューを実行する.
process.nextTick()
まずみんなに一つの定義をtickと言います.一つのtickは一つのイベント周期を指します.process.nextTickとは、次のイベントのサイクルtickが始まる前に、この関数を呼び出します.
process.nextTick(() => {
  console.log('i am the next tick');
})
したがって、nextTickは、メッセージキューのsetTimeoutよりも速くなければならない.
set Immedite()
nodejsは、できるだけ早くコードを実行するsetImmediate方法を提供します.
setImmediate(() => {
  console.log('I am immediate!');
})
setImmediteの関数は、イベントサイクルの次の反復で実行されます.
setImmedite()とsetTimeout(()=>{}0)の機能は基本的に似ています.これらはいずれもイベントサイクルの次の反復で実行されます.
set Interval()
タイミングであるコールバック関数を実行するには、set Intervalが必要です.
setInterval(() => {
  console.log('  2     ');
}, 2000)
上記のタイミングタスクをクリアするには、clear Intervalを使用できます.
const id = setInterval(() => {
  console.log('  2     ');
}, 2000)

clearInterval(id)
なお、set Intervalは、関数が実行されたかどうかにかかわらず、nミリ秒ごとに関数を起動する.
一つの関数の実行時間が長すぎると、次の関数が同時に実行される場合、どうやってこの問題を解決しますか?
再帰的なsetTimeout呼び出しを形成するように、コールバック関数内部で再度呼び出すことを考慮することができる.
const myFunction = () => {
  console.log('   , 2s    !');

  setTimeout(myFunction, 2000)
}

setTimeout(myFunction, 2000)
本文の作者:flydeanプログラムのあれらの事
本論文のリンク:http://www.flydean.com/nodejs-event/
flydeanのブログ
私の公衆番号に注目してください.「プログラムに関すること」を最も分かりやすく解読し、最も深い商品、最も簡潔な教程、多くのあなたの知らない小さな技術などを発見してください.