毋庸置疑,大家都很了解js是一门单线程语言,这也就说明JS无法进行多线程,但是JS中异步的功能完全可以模拟多线程,而且效果还杠杠滴。当然,如果想完全理解异步,首先要了解JS的运行核心——事件环(Event Loop),下面分两部分理解事件环:
一:浏览器中的事件环(Event Loop)
- 为了能更好的理解JS在浏览器中的任务队列和事件循环,请看下图:
- eventLoop 是由JS的宿主环境(浏览器)来实现的;
- 事件循环可以简单的描述为以下四个步骤:
1. 函数入栈,当Stack中执行到异步任务的时候,就将他丢给WebAPIs,接着执行同步任务,直到Stack为空;2. 此期间WebAPIs完成这个事件,把回调函数放入队列中等待执行(微任务放到微任务队列,宏任务放到宏任务队列)3. 执行栈为空时,Event Loop把微任务队列执行清空;4. 微任务队列清空后,进入宏任务队列,取队列的第一项任务放入Stack(栈)中执行,回到第1步。复制代码
- 认识浏览器中的任务源(task):
- 微任务:then 、messageChannel 、mutationObersve
- 宏任务:setTimeout、setInterval、setTmmediate(只兼容ie)
- 下面实现一个小例子:
console.log(1);console.log(2);setTimeout(function () { console.log('setTimeout1'); Promise.resolve().then(function () { console.log('promise'); });});setTimeout(function () { console.log('setTimeout2');});复制代码
打印结果:
1
2 setTimeout1promise
setTimeout2
二:Node 环境中的事件环(Event Loop)
- 为了能更好的理解JS在Node环境中的任务队列和事件循环,请看下图:
-
图虽然有些乱,但是我们只需关心timers计时器阶段和poll轮询阶段,check检查阶段即可,clons关闭阶段以及微任务队列即可。
-
Node 环境中微任务是插缝执行,(如果执行宏任务的时候发现了微任务, 不会像浏览器一样执行了,而是将为微任务放到微任务队列中,等待整个宏 任务队列执行完毕或者达到执行上线后,下一个阶段开始的时候先执行 完微任务队列中的任务)。
- 认识Node中的任务源(task):
- 微任务: then 、nextTick 、 messageChannel 、mutationObersve
- 宏任务:setTimeout 、setInterval 、setImmediate 、io文件操作
- 例一:timeout、immediate 两个谁先执行不一定 取决于node的执行时间。
setTimeout(function () { console.log('setTimeout1');})setImmediate(function () { console.log('setImmediate2');});复制代码
打印结果有两种:
- 1) setTimeout1 setImmediate2
- 2) setImmediate2 setTimeout1
- 例二: 如果i/o文件操作以后就会先执行setImmediate,因为setImmediate在i/o文件操作后面的那个阶段执行,执行完setImmediate会在下一个阶段的时候再执行setTimeout (timers 计时器执行阶段)
let fs = require('fs');fs.readFile('1.log', function () { console.log('fs'); setTimeout(function () { console.log('timeout'); }); setImmediate(function () { console.log('mmiediate'); });});复制代码
打印顺序结果
- fs 、 miediate、 timeout
- 例三: 微任务中nextTIck 会比then先执行。
Promise.resolve().then(function () { console.log('then2'):});process.nextTick(function () { console.log('nextTick1');});复制代码
打印顺序结果
- nextTick1 then2
- 例四: 微任务会优先与i\o文件操作执行。
let fs = require('fs');fs.readFile('./1/log',function(){ console.log('fs')})process.nextTick(function(){ console.log('text2');})复制代码
打印执行结果
- text2 fs
好了,今天就到这,如有错误,请下方留言。作为码农一枚,最大的愿望和最伟大的理想是,大宝天天见,bug死生不复相见,相忘于江湖,恩怨一笔消失!!!