JavaScript 事件循环机制

简介: javascript是一门单线程的非阻塞的脚本语言。单线程意味着javascript在执行代码的任何时候,都只有一个主线程来处理所有的任务。

javascript是一门单线程的非阻塞的脚本语言。单线程意味着javascript在执行代码的任何时候,都只有一个主线程来处理所有的任务。


那么javascript引擎是如何实现这一点的呢?


因为事件循环(event loop)。先上图:


image.png


图片解读:


  • 同步和异步任务分别进入不同的执行场所,同步的进入主线程,异步的进入Event Table并注册函数


  • 当指定的事情完成时(重点)Event Table会将这个函数移入Event Queue


  • 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行


  • 上述的过程会不断的重复,也就是常常说的Event Loop(事件循环)


简单例子


我们来一个简单的例子来说明下:


console.log('1');
setTimeout(() => {
  console.log('2');
}, 0)
console.log('3');


上面的代码将输出下面的结果:


1
3
2


因为setTimeout是一个异步的任务,所以会在最后才执行。


那么,我们来个复杂点的例子:


复杂例子


console.log('1');
 setTimeout(() => {
  console.log('2')
 }, 1000);
 new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('3');
  }, 0);
  console.log('4');
  resolve();
  console.log('5');
 }).then(() => {
  console.log('6');
 });
 console.log('7');


上面的代码输出的结果是:


1
4
5
7
6
3
2


看到这代码的时候是不是有些蒙圈?在我们揭开谜底之前,先来了解下微任务和宏任务


微任务和宏任务


微任务和宏任务都是异步的任务,他们都属于队列,主要区别是它们的执行顺序--微任务会比宏任务先执行。


宏任务包含有:setTimeout, setInterval, setImmediate, I/O, UI rendering


微任务包含有:process.nextTick, promise.then, MutationObserver


嗯~回到上面的代码,如下:


console.log('1');
 setTimeout(() => {
  console.log('2')
 }, 1000);
 new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('3');
  }, 0);
  console.log('4');
  resolve();
  console.log('5');
 }).then(() => {
  console.log('6');
 });
 console.log('7');


在执行到new Promise的时候会立马新建一个promise对象并立即执行。所以会输出 1,4,5,而then则会在Event Table中注册成回调函数并放在微任务队列中,而两个setTimeout(输出3)和setTimeout(输出2,1s后完成的啊)会被先后注册成回调函数并放在宏任务队列中。


理解了上面的一些原理之后,我们再来练下手...


console.log(1)
process.nextTick(() => {
  console.log(8)
  setTimeout(() => {
    console.log(9)
  })
})
setTimeout(() => {
  console.log(2)
  new Promise(() => {
    console.log(11)
  })
})
let promise = new Promise((resolve,reject) => {
  setTimeout(() => {
    console.log(10)
  })
  resolve()
  console.log(4)
})
fn()
console.log(3)
promise.then(() => {
  console.log(12)
})
function fn(){
  console.log(6)
}


得到的结果是:


1
4
6
3
8
12
2
11
10
9


客官可以画下图整理下思路,然后代码运行验证一下啊💨


相关文章
|
16天前
|
设计模式 JavaScript API
Node.js 事件循环
Node.js 事件循环
16 2
|
1月前
|
前端开发 JavaScript UED
深入理解JavaScript中的事件循环机制
JavaScript中的事件循环机制是其异步编程的核心,深入理解该机制对于开发高效、流畅的前端应用至关重要。本文将介绍事件循环的工作原理、常见的事件循环模型,以及如何利用这些知识解决前端开发中的常见问题。
|
1月前
|
Web App开发 JavaScript 前端开发
浏览器与Node.js事件循环:异同点及工作原理
浏览器与Node.js事件循环:异同点及工作原理
|
9天前
|
设计模式 JavaScript 前端开发
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
JavaScript的继承机制基于原型链,它定义了对象属性和方法的查找规则。每个对象都有一个原型,通过原型链,对象能访问到构造函数原型上的方法。例如`Animal.prototype`上的`speak`方法可被`Animal`实例访问。原型链的尽头是`Object.prototype`,其`[[Prototype]]`为`null`。继承方式包括原型链继承(通过`Object.create`)、构造函数继承(使用`call`或`apply`)和组合继承(结合两者)。ES6的`class`语法是语法糖,但底层仍基于原型。继承选择应根据需求,理解原型链原理对JavaScript面向对象编程至关重要
23 7
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
|
13天前
|
存储 前端开发 JavaScript
JavaScript 事件循环的详细描述
【6月更文挑战第15天】JavaScript事件循环是单线程非阻塞I/O的关键,通过调用栈跟踪同步函数,任务队列存储异步任务,事件循环在调用栈空时从队列取任务执行。当遇到异步操作,回调函数进入队列,同步代码执行完后开始事件循环,检查并执行任务。微任务如Promise回调在每个宏任务结束时执行,确保不阻塞主线程,优化用户体验。
28 6
|
16天前
|
JavaScript 前端开发
深入解析JavaScript中的面向对象编程,包括对象的基本概念、创建对象的方法、继承机制以及面向对象编程的优势
【6月更文挑战第12天】本文探讨JavaScript中的面向对象编程,解释了对象的基本概念,如属性和方法,以及基于原型的结构。介绍了创建对象的四种方法:字面量、构造函数、Object.create()和ES6的class关键字。还阐述了继承机制,包括原型链和ES6的class继承,并强调了面向对象编程的代码复用和模块化优势。
24 0
|
1月前
|
缓存 移动开发 JavaScript
WKWebView对网页和js,css,png等资源文件的缓存机制及如何刷新缓存
WKWebView对网页和js,css,png等资源文件的缓存机制及如何刷新缓存
48 1
|
1月前
|
开发框架 JavaScript 前端开发
JavaScript的事件循环机制是其非阻塞I/O的关键
【5月更文挑战第13天】JavaScript的事件循环机制是其非阻塞I/O的关键,由调用栈、事件队列和Web APIs构成。当异步操作完成,回调函数进入事件队列,待调用栈空时,事件循环取队列中的任务执行。在游戏开发中,事件循环驱动游戏循环更新,包括输入处理、游戏逻辑更新和渲染。示例代码展示了如何模拟游戏循环,实际开发中则常使用游戏框架进行抽象处理。
49 4
|
1月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包机制
闭包是JavaScript中一个重要且常被误解的概念。本文将深入探讨闭包的本质、工作原理以及在实际开发中的应用。通过详细解析闭包的定义、作用域链、内存管理等方面,读者将对闭包有更清晰的理解,并能够运用闭包解决实际开发中的问题。