Js运行机制(Event Loop)

174 阅读3分钟

事件循环机制

1、事件

JavaScript是一门单线程的,非阻塞的脚本语言

单线程: 任何时候都只有一个主线程(执行栈)处理所有任务

非阻塞:有异步任务时,js会产生一个任务队列,任务队列中的任务不会立即执行,当主线程任务执行完毕,则检查任务队列中是否

有回调,有则压入主线程执行

JS执行机制可以看做一个主线程加上一个任务队列.

同步任务都在主线程(这里的主线程就是JS引擎线程)上执行,会形成一个执行栈

主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放一个事件回调

一旦执行栈中的所有同步任务执行完毕(也就是JS引擎线程空闲了),系统就会读取任务队列,将可运行的异步任务(任务队列中的事件

回调,只要任务队列中有事件回调,就说明可以执行) 添加到执行栈中,开始执行。

js执行期间,同步任务都在执行栈中执行,异步任务则被压入任务队列,当同步任务执行完成,则读取任务队列中的任务,当任务队

列中有事件回调,则将其添加到执行栈中开始执行

2、事件循环

取自《深入浅出VueJs》p160,什么是事件循环

处理异步任务时,任务队列有宏任务队列微任务队列之分,

当执行栈中的任务都执行完毕之后,会去检查微任务队列中是否有事件存在, 如果有,则依次执行微任务队列中事件的回调,直到

执行栈清空;

然后去检查宏任务队列中是否有事件存在,如果有,则依次执行微任务队列中事件的回调,直到执行栈清空;

最后再去检查微任务队列中是否有事件存在,如此循环重复该过程,叫做事件循环

事件循环解释如下:👇👇👇👇👇👇👇👇👇👇👇👇

image-20220214101822938

3、宏任务、微任务

宏任务

我们可以将每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行), 每一个宏任务会从头到尾执行完毕,不会执行其他

由于JS引擎线程GUI渲染线程是互斥的关系,浏览器为了能够使宏任务DOM任务有序的进行,会在一个宏任务执行结果后,在下一个宏任务执行前,GUI渲染线程开始工作,对页面进行渲染

宏任务 --> GUI 渲染 --> 宏任务

常见的宏任务

主代码块

  • setTimeout
  • setInterval
  • setImmediate ()-Node
  • requestAnimationFrame ()-浏览器

微任务

我们已经知道宏任务结束后,会执行渲染,然后执行下一个宏任务, 而微任务可以理解成在当前宏任务执行后立即执行的任务

当一个宏任务执行完,会在渲染前,将执行期间所产生的所有微任务都执行完

宏任务 -> 微任务 -> GUI渲染 -> 宏任务 -> ...

常见微任务

  • process.nextTick ()-Node
  • Promise.then()
  • catch
  • finally
  • Object.observe
  • MutationObserver
4、练习
setTimeout(() => {
	console.log(1);
}, 0);

Promise.resolve().then(() => {
	console.log(2);
});

const test = () => {
	return new Promise((resolve, reject) => {
		console.log(3);
		resolve(4);
		console.log(5);
		reject(6);
		console.log(7);
	});
};

test()
	.then(val => {
		console.log(8);
		console.log(val);
	})
	.catch(err => {
		console.log('err',err);
	}).finally(() => {
    console.log(9);
  });

console.log(10);

考察知识点:

1、同步任务、异步任务

2、宏任务微任务

3、Promise构造函数是同步执行的,then方法是异步执行的

4、Promise resolve reject执行问题