ホームページ  >  記事  >  ウェブフロントエンド  >  jsエンジンの実行仕組みを詳しく解説

jsエンジンの実行仕組みを詳しく解説

小云云
小云云オリジナル
2018-03-31 17:11:112962ブラウズ


この記事では主にjsエンジンの実行機構について詳しく解説し、皆様のお役に立てれば幸いです。

まず、2つの点に留意してください:

  • jsはシングルスレッド言語です

  • jsのイベントループはjsの実行機構です。 js の実行を深く理解することは、js のイベント ループを深く理解することに相当します

なぜ js はシングルスレッドなのでしょうか?

js は元々ブラウザーで使用されるように設計されているため、ブラウザー内の js がマルチスレッドである場合を想像してください。

シナリオの説明:

これで、プロセス 1 とプロセス 2 の 2 つのプロセスが存在し、同時に同じ dom 上で動作します。 process1 は dom を削除し、process2 は dom を編集して発行します。 2 つの相反するコマンドを同時に実行した場合、ブラウザはそれらをどのように実行すればよいでしょうか?

このように考えると、js がシングルスレッドになるように設計されている理由が簡単に理解できるはずです。

なぜ js に非同期が必要なのでしょうか?

シーンの説明;

js に非同期がない場合、前の行の解析時間が非常に長い場合、次のコードはブロックされます。ユーザーにとって、ブロックは「スタック」を意味し、ユーザー エクスペリエンスの低下につながります。

つまり、jsには非同期実行があります。

単一スレッドはどのようにして非同期実装を実現するのでしょうか?

JS はシングルスレッドで 1 つのスレッドでしか実行できないのに、どうすれば非同期にできるのでしょうか?

JS の実行メカニズムを理解できるのはイベント ループ (イベント ループ) です。

jsのイベントループ(1)

console.log(1);
setTimeout(function() {
  console.log(2);
}, 0);
console.log(3);// 输出 1 3 2

つまり、setTimeoutの関数はすぐに実行されるのではなく、一定期間遅延して、特定の条件が満たされた後に実行されるこのタイプのコードは、非同期と呼ばれます。コード。

それでは、ここでまず、JS におけるタスクを同期タスクと非同期タスクに分ける分類方法を知ります

この分類方法によると、js の実行メカニズムは次のようになります:

  • まず、js が同期でも非同期でも、同期であればメインスレッドに入り、非同期であればイベントテーブルに入ります

  • 非同期タスクはトリガー条件が満たされると、イベントテーブルに関数を登録します。それらはイベント キューにプッシュされます

  • 同期タスクはメイン スレッドに入ります。スレッドはメイン スレッドがアイドル状態になるまで実行を続け、その後イベント キューをチェックして、実行可能な非同期タスクがあるかどうかを確認します。 、メインスレッドにプッシュされます。

上記の 3 ステップのループ実行はイベント ループです

それでは、上記の例について、その実行順序を説明できますか?

console.log(1); // 同步任务,放入主线程中setTimeout(function() {
  // 异步任务,放到event table中,0秒后被推入到event queue中
  console.log(2);
}, 0);
console.log(3); // 同步任务,放到主线程中// 输出 1 3 2// 当1,3被打印后,主线程去event queue(事件队列)里查看是否有可执行的函数,执行setTimeout里面的函数。

jsのイベントループ(2)

次の例を見てください:

setTimeout(function() {
  console.log("定时器开始");
}, 0);new promise(function(resolve) {
  console.log("马上执行for循环了");
}).then(function(resolve) {
  console.log("执行then函数拉");
});
console.log("代码执行结束");

前にまとめたjsの実行メカニズムを使用して分析します:

setTimeout 是异步任务,放在 event table中new promise是同步任务,被放到主线程中,直接打印console.log('马上执行for循环了');

.then里面的是异步任务,被放到event table中

console.log('代码执行结束') 是同步代码,被放在主线程中,直接执行。

つまり、結果は[forループをすぐに実行します - コードの実行が終了します -タイマーが開始されました – then 関数が実行されました]?

自分で実行した結果はこのようにはなりませんでしたが、[for ループがすぐに実行されます – コードの実行が終了します – then 関数が実行されます – タイマーが開始します]

では、非同期タスクの実行順序は前後の順序ではなく、別の規定があるのではないでしょうか? 実は、非同期と同期の分け方によると、正確ではありません

正確な分け方は:

  • macro-task (マクロタスク) Task): 全体のコードスクリプト、setTimeout、setInterval

  • micro-task (マイクロタスク): Promise、process、nextTick

jsエンジンの実行仕組みを詳しく解説

によるとこの分類に従えば、js の実行メカニズムは次のようになります。

  • マクロタスクを実行する際、プロセス中にマイクロタスクが発生した場合、現在のマクロタスクが完了した後、それをマイクロタスクのイベントキューに入れます。マイクロタスクのイベントキューがチェックされ、その中のすべてのマイクロタスクが順番に追加されます。

  • 上記の 2 つの手順を繰り返し、イベント ループ(1) イベント ループ(2) を組み合わせて、より正確な JS 実行メカニズムを取得します。

  • 今のメカニズムに従って、例 2 を分析してください:
// 首先执行script下的宏任务,遇到setTimeout,将其放在宏任务队列中setTimeout(function() {
  console.log("定时器开始");
}, 0);// 遇到new promise直接执行new promise(function(resolve) {
  console.log("马上执行for循环了");
}).then(function(resolve) {
  // .then方法,是微任务,放在微任务队列中
  console.log("执行then函数拉");
});
console.log("代码执行结束");// 宏任务执行完毕,查看本轮的微任务,返现有一个then方法。再去执行宏任务队列中的函数。

setTimeout について話します

この setTimeout コードは何を意味しますか? 一般に、3 秒後に setTimeout の関数が実行されると言われます

setTimeout(function() {
  console.log("执行了");
}, 3000);

しかし、これは違います。 true 厳密かつ正確な説明は次のとおりです。3 秒後に、setTimeout の関数がイベント キューにプッシュされ、イベント キュー (イベント キュー) 内のタスクはメイン スレッドがアイドル状態の場合にのみ実行されます。

つまり、(1) 3 秒後 (2) メインスレッドがアイドル状態で、両方が満たされる場合にのみ、関数は 3 秒後に実行されます

メインスレッドが大量のコンテンツを実行すると、実行時間が超過します3秒、たとえば10秒の場合、この関数は10秒後にのみ実行できます

JSエンジンの実行メカニズムを深く理解する

まず、次の2点に留意してください:

jsはシングルスレッド言語です

  • jsのイベントループはjsの実行メカニズムです。 js の実行を深く理解することは、js のイベント ループを深く理解することに相当します

  • なぜ js はシングルスレッドなのでしょうか?

  • js は元々ブラウザーで使用されるように設計されているため、ブラウザー内の js がマルチスレッドである場合を想像してください。

シーンの説明:

那么现在有 2 个进程,process1 process2,由于是多进程的 js,所以他们对同一个 dom,同时进行操作,process1 删除了该 dom,而 process2 编辑了该 dom,同时下达 2 个矛盾的命令,浏览器究竟该如何执行呢?

这样想,js 为什么被设计成单线程应该就容易理解了吧。

js 为什么需要异步?

场景描述;

如果 js 中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。对于用户而言,阻塞就意味着‘卡死’,这样就导致了很差的用户体验。

所以,js 中存在异步执行。

单线程又是如何实现异步的呢?

既然 JS 是单线程的,只能在一条线程上执行,又是如何实现的异步呢?

是通过的事件循环(event loop), 就理解了 js 的执行机制。

js 中的 event loop(1)

console.log(1);
setTimeout(function() {
  console.log(2);
}, 0);
console.log(3);// 输出 1 3 2

也就是说,setTimeout 里的函数并没有立即执行,而是延迟了一段时间,满足一定条件后,才去执行的,这类代码,我们叫异步代码。

所以,这里我们首先知道了 JS 里的一种分类方式,就是将任务分为: 同步任务和异步任务

按这种分类方式,js 的执行机制就是:

  • 首先判断 js 是同步的还是异步的,同步的就进入主线程,异步就进入 event table

  • 异步任务在 event table 中注册函数,当满足触发条件后,被推入 event queue

  • 同步任务进入主线程后一直执行,直到主线程空闲,才会去 event queue 中查看是否有可执行的异步任务,若果有就推入到主线程中。

以上三步循环执行,就是 event loop

所以上述例子,你是否可以描述他们的执行顺序了?

console.log(1); // 同步任务,放入主线程中setTimeout(function() {
  // 异步任务,放到event table中,0秒后被推入到event queue中
  console.log(2);
}, 0);
console.log(3); // 同步任务,放到主线程中// 输出 1 3 2// 当1,3被打印后,主线程去event queue(事件队列)里查看是否有可执行的函数,执行setTimeout里面的函数。

js 中的 event loop(2)

再看下一个例子:

setTimeout(function() {
  console.log("定时器开始");
}, 0);new promise(function(resolve) {
  console.log("马上执行for循环了");
}).then(function(resolve) {
  console.log("执行then函数拉");
});
console.log("代码执行结束");

用之前总结的 js 执行机制去分析:

setTimeout 是异步任务,放在 event table中new promise是同步任务,被放到主线程中,直接打印console.log('马上执行for循环了');

.then里面的是异步任务,被放到event table中

console.log('代码执行结束') 是同步代码,被放在主线程中,直接执行。

所以,结果是 【马上执行 for 循环啦 — 代码执行结束 — 定时器开始啦 — 执行 then 函数啦】吗?

亲自执行后,结果居然不是这样,而是【马上执行 for 循环啦 — 代码执行结束 — 执行 then 函数啦 — 定时器开始啦】

那么,难道是异步任务的执行顺序,不是前后顺序,而是另有规定? 事实上,按照异步和同步的划分方式,并不准确

而准确的划分方式是:

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

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

jsエンジンの実行仕組みを詳しく解説

按照这种分类方式,js 的执行机制就是:

  • 执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的 event queue 中

  • 当前宏任务执行完成后,会常看微任务的 event queue ,并将里面全部的微任务依次执行完。

重复以上 2 步骤,结合 event loop(1) event loop(2) ,就是更为准确的 JS 执行机制了。

按照刚才的机制,分析例 2:

// 首先执行script下的宏任务,遇到setTimeout,将其放在宏任务队列中setTimeout(function() {
  console.log("定时器开始");
}, 0);// 遇到new promise直接执行new promise(function(resolve) {
  console.log("马上执行for循环了");
}).then(function(resolve) {
  // .then方法,是微任务,放在微任务队列中
  console.log("执行then函数拉");
});
console.log("代码执行结束");// 宏任务执行完毕,查看本轮的微任务,返现有一个then方法。再去执行宏任务队列中的函数。

谈谈 setTimeout

这段 setTimeout 代码什么意思? 我们一般说: 3 秒后,会执行 setTimeout 里的那个函数

setTimeout(function() {
  console.log("执行了");
}, 3000);

但是这种说并不严谨,准确的解释是: 3 秒后,setTimeout 里的函数被会推入 event queue,而 event queue(事件队列)里的任务,只有在主线程空闲时才会执行。

所以只有满足 (1)3 秒后 (2)主线程空闲,同时满足时,才会 3 秒后执行该函数

如果主线程执行内容很多,执行时间超过 3 秒,比如执行了 10 秒,那么这个函数只能 10 秒后执行了

以上がjsエンジンの実行仕組みを詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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