浏览器/nodeJS中的EventLoop

大家都知道JS是一门单线程语言,也就意味着JS无法进行多线程,但是JS中异步的概念完全可以模拟多线程,而且效果差不到哪去

要完全理解异步,就需要了解 JS 的运行核心——事件循环(event loop)

但是在浏览器中运行JS和在nodeJS中运行还有一些差别,接下来我们就来看看这些差别在哪里

首先是浏览器中的EventLoop
在说浏览器EventLoop之前我们要先看看浏览器模型

浏览器模型.png
  • 用户界面 包括地址栏,书签栏等那些东西
  • 浏览器引擎 在用户界面,呈现引擎之间传送指令
  • 渲染引擎 也被称为呈现引擎
  • 请求(网络) 用于网络调用,比如HTTP请求
  • JS解释器 用于解析和执行JS代码
  • UI(用户界面后端) 用于绘制样式 和JS共用一个线程
  • 数据存储 浏览器需要保存的一些数据 不如Cookie

JS和css公用一个线程是因为浏览器不会同时渲染JS和css,一般都会先渲染css再执行JS

浏览器中的微任务
  then
  messageChannel
  mutationObersve

浏览器中的宏任务
  setTimeout
  setInterval

代码调用先进堆栈,堆栈是代码的总执行站,堆栈整个执行的过程中会先将微任务,宏任务放到相应的队列中,事件提出来等待触发,等到总执行站中的代码空了,会先看微任务队列中有没有,如果有就会放到总执行站中执行,然后在看宏任务队列中有没有。

浏览器EventLoop.png
setTimeout(function () {
    console.log('setTimeout')
})
Promise.resolve().then(function () {
      console.log('promise')
});
console.log('堆栈');

// 执行结果:
// 堆栈
// promise
// setTimeout

如果把微任务队列放到堆栈中执行的时候又发现了宏任务,会顺便吧微任务中的宏任务一起执行了

setTimeout(function () {
    console.log('setTimeout1')
    Promise.resolve().then(function () {
        console.log('promise')
    });
})
setTimeout(function () {
    console.log('setTimeout2');
});

// 执行结果:
// setTimeout1
// promise
// setTimeout2

然后是nodeJS运行环境中的EventLoop
nodeJS中的宏任务和微任务在浏览器的基础上有新增了几个
微任务
  then
  nextTick
  messageChannel
  mutationObersve

宏任务
  setTimeout
  setInterval
  setImmediate、

node的调用顺序中会比浏览器中的复杂一些

nodeJS EventLoop.png

看图虽然复杂,但是我们只需要关心timers计时器阶段,poll轮询阶段,check检查阶段(setImmediate回掉),clons关闭阶段以及微任务队列即可,因为处理网络,内部调用与咱们的宏任务和微任务的执行没有太大的关系
和浏览器运行环境不同的是微任务只会在阶段转化的时候才会调用,就是close关闭阶段后再执行下一阶段的时候

process.nextTick(function () {
    console.log('nextTick')
});
setImmediate(function () {
    console.log('setImmediate')
});

// 执行结果:
// nextTick
// setImmediate

如果宏任务执行的时候又发现微任务了,不会和浏览器一样顺便执行了,而是会将微任务再放到微任务队列中,等待整个阶段结束后,下一个阶段开始的时候先执行完微任务队列中的微任务

setTimeout(function () {
    console.log('setTimeout1')
    Promise.resolve().then(function () {
        console.log('promise')
    });
})
setTimeout(function () {
    console.log('setTimeout2');
});

// 执行结果:
// setTimeout1
// promise
// setTimeout2

反之亦然

process.nextTick(function () {
    console.log(1)
    setImmediate(function () {
        console.log(2);
    })
})
setImmediate(function () {
    console.log(3);
    process.nextTick(function () {
        console.log(4)
    })
})

// 执行结果:
// 1
// 3
// 2
// 4

timeout immediate 两个谁先执行不一定 取决于node的执行时间

setTimeout(function () {
    console.log('setTimeout');
})
setImmediate(function () {
    console.log('setImmediate')
});

// 执行结果:
// setTimeout
// setImmediate
// 或者:
// setImmediate
// setTimeout

但是加上i/o文件操作以后就会先执行setImmediate,因为setImmediate在i/o文件操作后面的那个阶段执行,执行完setImmediate会在下一个阶段的时候再执行setTimeout (timers 计时器执行阶段)

let fs = require('fs');
fs.readFile('./1.txt', function () {
    console.log('fs');
    setTimeout(function () {
        console.log('setTimeout');
    })
    setImmediate(function () {
        console.log('setImmediate')
    })
});

// 执行结果
// fs
// setImmediate
// setTimeout
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 蔡丽萍祝大家新年快乐!狗年发大财;幸福安康;心想事成;万事如意;洪福齐天;风光无限;笑口常开;好运连连;财源滚滚;...
    小草丽人阅读 3,647评论 0 0
  • 1. 捧着半儿拉西瓜挖着吃的时候 2. 躺在床上上无忧无虑发呆的时候 3. 上完一天班后躺在床上看电影,并拿着半儿...
    马雨_Val阅读 1,396评论 0 1
  • PHP是一门对新手友好的编程语言,规矩很少,内置函数和可扩展模块很多。最重要的是PHP官方手册十分详细而且有中文版...
    yxtm阅读 2,707评论 0 0
  • 云映日而成霞,泉挂岩而成瀑。所托者异,而名亦因之。此友道之所以可贵也。 如《颜氏家训》说:与善人居,如入芝兰之室,...
    转弯弯阅读 1,832评论 0 0

友情链接更多精彩内容