ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript の実行メカニズムについての深い理解

JavaScript の実行メカニズムについての深い理解

不言
不言オリジナル
2018-08-31 10:12:23986ブラウズ

この記事の内容は JavaScript の実行メカニズムを詳しく理解するためのものであり、必要な方は参考にしていただければ幸いです。

まず第一に、JavaScript がシングルスレッド言語であることは誰もが知っているので、次のように結論付けることができます:

JavaScript はステートメントの順序で実行されます

初見:

let a = '1'
console.log(a)

let b = '2'
console.log(b)

明らかに誰もが結果を知っており、順番に 1 を出力します, 2

ただし、別の方法:

setTimeout(function() {
    console.log(1)
})

new Promise(function(resolve) {
    console.log(2)
    for(var i = 0;i< 10;i++){
        i === 10 && resolve()
    }
}).then(function() {
    console.log(3)
})
console.log(4)

このとき、コードの順次実行を見て、1、2、3、4を出力します。さて、それをブラウザに入れて実行してみましょう。実際の出力は 2、4、3、1 です。約束通り順番に実行するのはどうでしょうか?次に、JavaScript の実行メカニズムを理解する必要があります。

シングルスレッド

まず第一に、JavaScript はシングルスレッド言語であり、Web ワーカーは最新の HTML5 で起動されましたが、シングルスレッド言語である JavaScript の核心は変わっていません。したがって、JavaScript マルチスレッドはシングル スレッドに基づいてシミュレートされます。したがって、JavaScript はシングルスレッド言語であることに留意してください。

イベントループ

タスクは2つのカテゴリに分類されます:

  • 同期タスク

  • 非同期タスク

ページを開くと、ページのレンダリングは読み込みなどの多くの同期タスクです。画像と音声 リソースを消費するタスクは非同期タスクです。タイム ループの主な内容は次のとおりです。

  1. タスクが実行スタックに入ると、それが同期タスクであるか非同期タスクであるかを判断し、同期タスクの場合は、実行のためにメインスレッドに入り、非同期に入ります。イベントテーブルに関数を登録します。

  2. 指定されたイベントが完了すると、イベントテーブルはこの関数をイベントキューに移動します

  3. メインスレッドのタスクが実行された後、タスクキューに移動して対応する関数を読み取り、メインスレッドに入ります実行用スレッド

  4. 上記のプロセスが継続的に繰り返され、イベントループが構成されます

jsエンジンには監視プロセスがあり、メインスレッドの実行スタックが空になったかどうかを常にチェックします。タイムキューに移動して、関数の呼び出しを待っているかどうかを確認します。

例:

setTimeout( function() {
    console.log(1)
}, 0)
console.log(2)
  • 最初にsetTimeoutがイベントテーブルに入ります

  • console.log(2)を実行します

  • setTimeoutによって実行された関数がイベントキューに入ります

  • メインスレッドが関数を読み取りますイベントキューからの実行

このため、setTimeout(fn, 0) 関数を設定しても、すぐには実行されません。ただし、メインスレッドが空であっても 0 ミリ秒に到達することはできません。HTML 標準によれば、最小値は 4 ミリ秒です。 setTimeout(fn, 0)函数也不会立即执行的原因。不过即使主线程为空,0ms也是达不到的,根据HTML标准,最低是4ms。

setInterval

还有一个与setTimeout类似的函数,对于setInterval来说,是循环执行。对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待。

但是需要注意的一点是,对于setInterval(fn, ms)来说,他并不是每过ms执行一次 ,而是每过 ms 会有fn进入任务队列。也就是说如果setInterval 的回调函数的执行事件如果超过延迟ms,那么就看不出来事件间隔了。

Promise 和 process.nextTick(callback)

除了广义的同步任务和异步任务之外,还有对任务更精细的划分,分为:

  • macro-task(宏任务):包括整体代码script、setTimeout、setInterval

  • micro-task(微任务):Promise、process.nextTick

事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

用一段代码来说明:

setTimeout(function() {
    console.log('1');
})

new Promise(function(resolve) {
    console.log('2');
    resolve()
}).then(function() {
    console.log('3');
})

console.log('4');
  • 这段代码作为宏任务,开始第一次循环

  • 先遇到setTimeout,那么它的回调函数进入到宏任务事件队列中

  • 遇到Promise,Promise立即执行,输出2,then任务进入到微任务事件队列中

  • 下面遇到console,输出4

  • 第一个宏任务结束,看微任务事件队列,执行then,输出3

  • 第一轮循环结束,看宏任务队列中存在setTimeout的回调函数执行,输出1

  • 所有结果为:2,4,3,1

好了了解了基本的原理之后,我们来看一个更复杂的:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

不知道大家答案是什么?接下来我们来进行分析一下:

第一轮:

  1. 首先整段代码作为一个宏任务进入主线程,首先遇到console.log()输出1

  2. 遇到第一个setTimeout()进入宏任务队列

  3. 遇到Process.nextTick()

    setInterval🎜🎜 setTimeout の場合はループ内で実行される、setTimeout と同様の関数もあります。実行シーケンスに関しては、setInterval により、登録された関数が指定された間隔でイベント キューに配置されます。前のタスクに時間がかかりすぎる場合は、待機する必要もあります。 🎜🎜しかし、注意すべき点が 1 つあります。それは、setInterval(fn, ms) の場合、ms が経過するたびに実行されるのではなく、ms が経過するたびに実行されるということです。 code> fn がタスクキューに入ります。つまり、setInterval のコールバック関数の実行イベントが遅延 ms を超える場合、イベント間隔は表示されません。 🎜🎜Promise と process.nextTick(callback)🎜🎜 一般的な同期タスクと非同期タスクに加えて、より詳細なタスクの分割もあります。コード全体のスクリプト、setTimeout、setInterval🎜🎜🎜🎜micro-task (micro-task): Promise、process.nextTick🎜🎜🎜🎜 イベントループの順序は、JS コードの実行順序を決定します。コード全体 (マクロ タスク) を入力すると、最初のサイクルが開始されます。次に、すべてのマイクロタスクを実行します。次に、再度マクロタスクから開始し、実行するタスクキューの 1 つを見つけて、すべてのマイクロタスクを実行します。 🎜🎜コードの一部を使用して説明します: 🎜rrreee🎜🎜🎜このコードはマクロ タスクとして機能し、最初のサイクルを開始します🎜🎜🎜🎜最初に setTimeout が発生し、次にそのコールバック関数がマクロに入りますタスク イベント キュー 🎜🎜🎜🎜 で Promise が発生し、Promise がすぐに実行され、2 が出力され、then タスクがマイクロタスク イベント キューに入ります。 🎜🎜 🎜🎜以下にコンソールが表示されます。出力 4🎜🎜🎜🎜最初のマクロタスクが終了し、マイクロタスクイベントキューを確認し、then を実行して、出力 3🎜🎜🎜🎜 ループの最初のラウンド終了したら、マクロを見てください タスクキューに setTimeout コールバック関数の実行があり、出力は 1 です🎜🎜🎜🎜 結果はすべて 2、4、3、1 です🎜🎜🎜🎜 さて、基本原理を理解したところで、もっと複雑なものを見てみましょう: 🎜rreee 🎜あなたの答えがわかりません?次に、分析してみましょう: 🎜🎜第 1 ラウンド: 🎜🎜🎜🎜まず、コード全体がマクロ タスクとしてメイン スレッドに入り、最初に console.log() に遭遇し、1 を出力します🎜🎜🎜 🎜最初の setTimeout() に遭遇し、マクロ タスク キューに入ります🎜🎜🎜🎜 Process.nextTick() に遭遇し、マイクロ タスク キューに入ります🎜
  4. その後、Promise が発生し、すぐに実行され、出力 7 が出力され、その後 がマイクロタスク キューに追加されます Promise,立即执行,输出7,then被添加到微任务队列

  5. 遇到第二个setTimeout,进入宏任务队列

  6. 然后执行两个微任务

  7. 执行Process.nextTick()输出6

  8. 执行then,输出8

这样第一轮循环就彻底结束了,进行第二轮事件循环,也就是第一个setTimeout

  1. 首先遇到console.log(),输出2

  2. 遇到Process.nextTick(),进入微任务队列

  3. 遇到Promise立即执行输出4,then进入微任务队列

  4. 然后执行第一个微任务,输出3

  5. 执行then,输出5

这样第二轮事件循环就结束了,最后执行第二个setTimeout,第二个setTimeout和上面原理类似,也就不重复说明了。所以最终结果是:1,7,6,8,2,4,3,5,9,11,10,12

2 番目の setTimeout code> が発生し、マクロタスクキューに入ります<p><a href="http://www.php.cn/js-tutorial-388552.html" target="_self"></a><br> そして、2つのマイクロタスクを実行します</p> <p><a href="http://www.php.cn/js-tutorial-388866.html" target="_self"></a> <code>Process.nextTick()を実行し、6を出力します

🎜 thenを実行し、出力します8🎜🎜🎜このようにして、ループの最初のラウンドが完全に終了し、最初の setTimeout🎜
    🎜🎜最初に console.log() が発生し、出力 2 が発生しました🎜🎜🎜🎜 Process.nextTick() が発生し、マイクロタスク キューに入りました🎜🎜 🎜🎜 Promise に移動して出力 4 をすぐに実行し、その後 がマイクロタスク キューに入ります 🎜🎜🎜🎜 そして最初のマイクロタスクを実行し、出力 3 を実行します🎜🎜🎜🎜その後、出力 5🎜 🎜
🎜 このようにして、イベント ループの 2 回目のラウンドが終了し、最後に 2 番目の setTimeout が実行されます。2 番目の setTimeout は、原則は上記なので説明は省略します。最終結果は次のようになります: 1,7,6,8,2,4,3,5,9,11,10,12🎜🎜 関連する推奨事項: 🎜🎜🎜 js 実行メカニズムの詳細な説明例🎜🎜 🎜🎜🎜JavaScript実行メカニズムのイベントループ🎜🎜🎜🎜

以上がJavaScript の実行メカニズムについての深い理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。