浅入浅出javascript执行机制

232 阅读4分钟

1.主要内容

主要内容是讲javascript的执行机制。以及对Event Loop的解释,以下内容中js执行的宿主环境是浏览器端,在nodeJs中某些细微的地方可能会有些差异,但执行机制还是一样的。

2.一些基本概念

javascrip的执行是单线程,也就是一次执行一个任务,多个任务就要一个一个排队执行,但是如果要执行一个耗时很长的任务,那就会阻塞后续代码的执行,因此JS就有了Event Loop机制去实现异步任务。

3.同步代码执行

Javascript引擎(JavaScript Engine)都不陌生,最著名的就是V8了,js引擎就是解释 并执行JS代码的,它一行一行的遍历我们应用程序中的代码,并一次执行一行,所以我们的javascript就是单线程的了, 不会同时执行多行代码。

先来看看同步代码的执行,这里要引入一个调用栈的概念(call stack),可以理解为javascript引擎一行行遍历我们应用程序代码,将遍历到的要执行的那行代码放到执行栈里, 然后执行,执行完后就把这行推出来,再取应用程序中的下一行。

接下来看这么个例子: 例子和图的思想取自文章:What is the JavaScript event loop?

/*main.js file */
var firstFunction = function () {
  console.log("I'm first!");
};

var secondFunction = function () {

  firstFunction();
  console.log("I'm second!");
};
secondFunction();

接下来js引擎执行main.js文件时call stack执行情况如下:

  1. main.js的执行,main.js可以看做是一个入口函数执行,此时call stack初始状态为:
  2. js引擎从上往下遍历,要执行的代码是secondFunction(),将其放入call stack中:
  3. 放入之后就执行这个函数,这个函数执行又调用了firstFunction(),将其放入执行栈中:
  4. 执行firstFunction(),控制台输出"I'm first!":
  5. firstFunction()执行完,移除执行栈:
  6. 继续执行secondFunction()后面的代码控制台输出"I'm second!":
  7. secondFunction()执行完毕,移出执行栈:
  8. main.js执行完了, 移除执行栈。
    至此,我们这个只有同步任务的代码已经执行完了,但是如果任务中会有一些耗时很长的任务,那么他将会阻塞后面同步代码的执行,因此接下来就要讲到js中的异步代码的执行了。

5.Event Loop (事件循环机制)

应用从程序中会有很多的异步操作,比如setTimeout,setInterval,ajax的请求等。因此这些异步代码是如何执行同时又不阻塞主线程的运行的呢。

Event Loop循环机制就是,主线程一行行执行代码, 遇到异步任务就将回调函数放入到Event Table中,主线程继续往下执行,不会被阻塞,当异步任务被触发了,就将回调函数推入到Event Queue中, 主线程始终一步步执行同步任务,直到执行完了,然后再将Event Queue中的回调函数推入call stack中执行,这样就形成了一个Event Loop的循环执行了。

6.含有异步代码的执行

接下来看这么个例子: 例子和图的思想还是取自文章:What is the JavaScript event loop?

var firstFunction = function () {
 console.log("I'm first!");
};

var secondFunction = function () {
 setTimeout(firstFunction, 5000);
 console.log("I'm second!");
};

secondFunction();
  1. 第一、二、是和同步一样的,将secondFunction()放入到了call stack中,然后执行,此时需要执行一个异步方法,在setTimeout执行之前是如下情况:

  2. setTimeout执行完之后,setTimeout推出call stack回调函数firstFunction会放入到EventTable中。

  3. 主线程继续执行secondFunction(),控制台输出I'm second!,secondFunction()推出call stack, 此时5s还未到:

  4. main.js执行完了,call stack 未空了, 5s还未到:

  5. 5s时间到了,Event table监听到了这个事件,将对应的回调函数firstFunction放入到Event Queue中:

  6. Event Loop机制监控到call stack 为空,且Event Queue有函数firstFunction(),因此将该函数推入新的call stack中开始又一轮的执行:

在主线程的执行过程中,Event table一直会监听是否有特定事件触发,然后将回调放入到Event Queue中。 同时事件循环机制会监控call stack是否为空, 如果为空就会将Event Queue中的回到函数推入一个新的call stack中,重新又开始一轮主线程执行。

7.后记

本文是结合一些其他文章学习以及自己理解的总结性文章,如有不对之处还请轻喷并给予指出,如能无意中对某些小伙伴略有帮助将不甚荣幸!!!!