四、线程机制与事件机制
1、进程与线程
Ⅰ- 进程
Ⅱ-线程
Ⅲ-进程与线程
Ⅳ-引出的问题
① 何为多进程与多线程?
② 比较单线程与多线程?
③ JS是单线程还是多线程?
④ 浏览器运行是单线程还是多线程?
⑤ 浏览器运行是单进程还是多进程?
2、浏览器内核
Ⅰ-不同浏览器的内核
Ⅱ-内核由什么模块组成?
3、定时器引发的思考
Ⅰ-定时器真是定时执行的吗?
Ⅱ-定时器回调函数是在分线程执行的吗?
Ⅲ-定时器是如何实现的?
3、JS是单线程的
Ⅰ-如何证明JS执行是单线程的
Ⅱ-JS引擎执行代码的基本流程与代码分类
Ⅲ-为什么js要用单线程模式, 而不用多线程模式?
4、事件循环模型(Event Loop)机制
Ⅰ-概念引出
单线程是必要的
:
当然,现如今人们也意识到,单线程在保证了执行顺序的同时也限制了javascript的效率,因此开发出了web workers
技术。这项技术号称可以让javaScript成为一门多线程语言。
可以预见,未来的javascript也会一直是一门单线程的语言。
话说回来,前面提到javascript的另一个特点是“非阻塞
”,那么javascript引擎到底是如何实现的这一点呢?
注:虽然nodejs中的也存在与传统浏览器环境下的相似的事件循环。然而两者间却有着诸多不同,故把两者分开,单独解释
。
Ⅱ-浏览器环境下JS引擎的事件循环机制
① 执行栈概念
当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境
。这个过程反复进行,直到执行栈中的代码全部执行完毕。
此处继续拿出栈图加深理解:
② 事件队列(Task Queue)
这里还有一张图来展示这个过程:
Ⅲ-宏任务(macro task)与微任务(micro task)
① 宏任务队列与微任务队列解释
② 原理图
③ 由代码逆向理解宏任务与微任务
Ⅳ-node环境下的事件循环机制
① 与浏览器环境有何不同?
② 事件循环模型
③ 事件循环各阶段详解
这些阶段大致的功能如下:
- timers(定时器检测阶段): 这个阶段执行定时器队列中的回调如
setTimeout()
和setInterval()
。 - I/O callbacks(I/O事件回调阶段): 这个阶段执行几乎所有的回调。但是不包括close事件,定时器和
setImmediate()
的回调。 - idle, prepare: 这个阶段仅在内部使用,可以不必理会。
- poll(轮询阶段): 等待新的I/O事件,node在一些特殊情况下会阻塞在这里。
- check(检查阶段):
setImmediate()
的回调会在这个阶段执行。 - close callbacks(关闭事件回调阶段): 例如
socket.on('close', ...)
这种close事件的回调。
下面我们来按照代码第一次进入libuv引擎后的顺序来详细解说这些阶段:
poll(轮询阶段)
check(检查阶段)
close callbacks(关闭事件回调阶段)
timers(定时器检测阶段)
I/O callbacks(I/O事件回调阶段)
④ process.nextTick,setTimeout与setImmediate的区别与使用场景
这三者间存在着一些非常不同的区别: