前言
大家都知道js是单线程的脚本语言,在同一时间,只可以做同一件事,为了协调事件、使用户交互、脚本、UI渲染和网络解决等行为,防止主线程阻塞,Event Loop方案应运而生...为什么js是单线程?
js作为主要运行在浏览器的脚本语言,js主要使用途之一是操作DOM。
在js高程中举过一个栗子,假如js同时有两个线程,同时对同一个dom进行操作,这时浏览器应该听哪个线程的,如何判断优先级?
为了避免这种问题,js必需是一门单线程语言,并且在未来这个特点也不会改变。
执行栈与任务队列
由于js是单线程语言,当遇到异步任务(如ajax操作等)时,不可可以一直等待异步完成,再继续往下执行,在这期间浏览器是空闲状态,显而易见这会导致巨大的资源白费。
执行栈
当执行某个函数、使用户点击一次鼠标,Ajax完成,一个图片加载完成等事件发生时,只需指定过回调函数,这些事件发生时就会进入执行栈队列中,等待主线程读取,遵循先进先出准则。
主线程
要明确的一点是,主线程跟执行栈是不同概念,主线程规定现在执行执行栈中的哪个事件。
主线程循环:即主线程会不停的从执行栈中读取事件,会执行完所有栈中的同步代码。
当遇到一个异步事件后,并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不同的队列中,我们称之为任务队列(Task Queue)。
当主线程将执行栈中所有的代码执行完之后,主线程将会去查看任务队列能否有任务。假如有,那么主线程会依次执行那些任务队列中的回调函数。
不太了解的话,能运行一下下面的代码,或者者点击一下这个demo
结果是当a、b、c函数都执行完成之后,三个setTimeout才会依次执行。
pre class="brush:js;toolbar:false">let a = () => { setTimeout(() => { console.log('任务队列函数1') }, 0) for (let i = 0; i < 5000; i++) { console.log('a的for循环') } console.log('a事件执行完')}let b = () => { setTimeout(() => { console.log('任务队列函数2') }, 0) for (let i = 0; i < 5000; i++) { console.log('b的for循环') } console.log('b事件执行完')}let c = () => { setTimeout(() => { console.log('任务队列函数3') }, 0) for (let i = 0; i < 5000; i++) { console.log('c的for循环') } console.log('c事件执行完')}a();b();c();// 当a、b、c函数都执行完成之后,三个setTimeout才会依次执行js 异步执行的运行机制。
宏任务与微任务:
异步任务分为 宏任务(macrotask) 与 微任务 (microtask),不同的API注册的任务会依次进入自身对应的队列中,而后等待 Event Loop 将它们依次压入执行栈中执行。
宏任务(macrotask)::
script(整体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)
微任务(microtask):
Promise、 MutaionObserver、process.nextTick(Node.js环境)
Event Loop(事件循环):
Event Loop(事件循环)中,每一次循环称为 tick, 每一次tick的任务如下:
宏任务 > 所有微任务 > 宏任务,如下图所示:
从上图我们能看出:
上面提到的demo结果能这么了解:先执行script宏任务,执行完了之后,再执行其余两个定时器宏任务。
面试题实践
下面这个题,很多人都应该看过/遇到过,重新来看会不会觉得清晰很多:
pre class="brush:js;toolbar:false"> // 执行顺序问题,考察频率挺高的,先自己想答案** setTimeout(function () { console.log(1); }); new Promise(function(resolve,reject){ console.log(2) resolve(3) }).then(function(val){ console.log(val); }) console.log(4);根据本文的解析,我们能得到:
根据本文的内容,能很轻松,且有理有据的猜出写出正确答案:2,4,3,1.
结语
相似上文的面试题还有很多,实则都大同小异,只需掌握了事件循环的机制,这些问题都会变得很简单。
作者:OBKoro1 原文链接:https://juejin.im/post/5b24b116e51d4558a65fdb70