导航
[[深刻01] 执行上下文](https://juejin.im/post/684490...
[[深刻02] 原型链](https://juejin.im/post/684490...
[[深刻03] 继承](https://juejin.im/post/684490...
[[深刻04] 事件循环](https://juejin.im/post/684490...
[[深刻05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490...
[[深刻06] 隐式转换 和 运算符](https://juejin.im/post/684490...
[[深刻07] 浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...
[[深刻08] 前端平安](https://juejin.im/post/684490...
[[深刻09] 深浅拷贝](https://juejin.im/post/684490...
[[深刻10] Debounce Throttle](https://juejin.im/post/684490...
[[深刻11] 前端路由](https://juejin.im/post/684490...
[[深刻12] 前端模块化](https://juejin.im/post/684490...
[[深刻13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490...
[[深刻14] canvas](https://juejin.im/post/684490...
[[深刻15] webSocket](https://juejin.im/post/684490...
[[深刻16] webpack](https://juejin.im/post/684490...
[[深刻17] http 和 https](https://juejin.im/post/684490...
[[深刻18] CSS-interview](https://juejin.im/post/684490...
[[深刻19] 手写Promise](https://juejin.im/post/684490...
[[深刻20] 手写函数](https://juejin.im/post/684490...
[[react] Hooks](https://juejin.im/post/684490...
[[部署01] Nginx](https://juejin.im/post/684490...
[[部署02] Docker 部署vue我的项目](https://juejin.im/post/684490...
[[部署03] gitlab-CI](https://juejin.im/post/684490...
[[源码-webpack01-前置常识] AST形象语法树](https://juejin.im/post/684490...
[[源码-webpack02-前置常识] Tapable](https://juejin.im/post/684490...
[[源码-webpack03] 手写webpack - compiler简略编译流程](https://juejin.im/post/684490...
[[源码] Redux React-Redux01](https://juejin.im/post/684490...
[[源码] axios ](https://juejin.im/post/684490...
[[源码] vuex ](https://juejin.im/post/684490...
js单线程
- 为什么js回事单线程?
设计js的目标是为了操作DOM等,如果是多线程,两个线程同时对同一个DOM元素执行了不同的操作,就会造成( 抢夺执行权 )的问题
过程和线程的区别
- 一个过程能够有多个线程
- 一个线程只能属于一个过程
- 过程有本人独立的地址空间,<font color=red>一个过程崩掉不会影响其余过程</font>
- 线程只是一个过程的不同执行门路,线程有本人的堆栈和局部变量,但线程之间没有独自的地址空间,<font color=red>一个线程死掉就等于整个线程死掉</font>
一些单词
- stack栈
- heap堆
- queue队列
- macro-task: 宏工作
- micro-task: 微工作
- execution-context:执行上下文
栈和队列
- 栈:后进先出
- 队列:先进先出
同步工作,异步工作
同步工作:在主线程上排队执行的工作,只有前一个工作执行结束,才会执行前面的工作 异步工作:未进入主线程,而进入工作队列的工作,只有"工作队列"告诉主线程,某个异步工作能够执行了,并且主线程的同步工作执行结束后,该工作才会进入主线程执行
事件循环
- 一个线程中,事件循环是惟一的,但 <font color=red>工作队列</font> 能够领有多个
- <font color=red>工作队列</font> 包含:
<font color=red>macro-task宏工作</font> ,和
<font color=red>micro-task微工作</font>,在新规范中别离叫做
<font color=red>task</font> 和
<font color=red>jobs</font> - macro-task包含:script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI render
- micro-task包含:Promise,process.nextTick,MutationObserver(html5新个性)
工作队列
- 工作队列分为宏工作(macro-task)和 微工作(micro-task)也叫 task 和 jobs
- 在一个线程中,工作队列能够有多个
宏工作
- 包含 script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI render
微工作
- 包含 Promise,process-nextTick,MutationObserver(html5新个性)
工作源和执行工作
- 工作源:setTimeout/setInterval等教程工作源
- 执行工作:<font color=red>进入工作队列的是工作源散发的执行工作,即回调函数</font>
- <font color=red>进入工作队列的是:工作源散发的执行工作,即回调函数</font>
setTimeout
- 立刻执行:setTimeout()函数自身是工作散发器,会立刻执行
延时执行:延时执行的是setTimeout的第一个参数,即回调函数,并且会进入macro-task
window.setTimeout(function() {console.log('timer')}, 100)// setTimeout(callback, delay)会立刻执行// setTimeout的一个参数会在dalay毫秒后执行,前提是同步工作执行的工夫要小于delay毫秒// setTimeout()执行时,进入函数调用栈,或者叫执行上下文栈,执行结束后,出栈// 而callback回调会在delay毫秒后进入工作队列,期待进入主线程// 工作队列:分为macro-task,micro-taskindow.setTimeout(function() {console.log('timer')}, 0)// setTimeout()的第二个参数是0,示意在执行完所有同步工作后,第一工夫执行回调// 对于setTimeout,即使主线程为空,0毫秒实际上也是达不到的。依据HTML的规范,最低是4毫秒
事件循环的程序!!!
- 事件循环的程序,决定了js代码的执行程序
- <font color=red>每一个工作的执行,无论是macro-task还是micro-task,都是借助函数调用栈来实现</font>
- 事件循环的程序:
- 事件循环从宏工作开始,即从script整体代码开始第一次循环
- 全局执行上下文进入函数调用栈(执行上下文栈),而后同步工作按调用程序顺次进入,同步工作进入主线程,异步工作进入分线程,定时器/事件等被浏览器的对应模块执行(定时器模块,事件处理模块),直到函数调用栈被清空(只剩全局,全局执行上下文永远在栈底)即同步工作执行完
- 而后执行工作队列中的微工作micro-task
- 当所有的micro-task微工作都执行实现后,循环再次从macro-task宏工作开始,而后再执行所有的micro-task,这样始终循环上来。
- 其中每一个工作的执行,无论是macro-task还是micro-task,都是借助函数调用栈(执行上下文栈)来实现的,即都是主线程的同步工作执行完后,工作队列的工作才进入主线程执行,即进入函数调用栈
解析:
(1) stack是执行上下文栈(函数调用栈),最底部是全局执行上下文,下面是初始化函数// 留神:函数分为初始化函数和回调函数,这样辨别只是为了更好的了解事件循环而已
<font color=red>(2) 比方定时器,js会把定时器的回调和工夫,交给浏览器的(定时器治理模块),在分线程下来执行,定时器治理模块仅仅是计时,工夫到后,把回调函数放入到工作队列callback queue中,期待进入主线程执行。</font>
(3) 比方事件,在事件产生的时候,浏览器的事件处理函数,会把回调放入到工作队列中
setTimeout(cb, delay)// setTimeout()进入函数调用栈执行完后,出栈// cb和dalay进入浏览器的分线程,被浏览器的定时器治理模块执行,在delay工夫后,将回调函数放入工作队列中// 有时候setTimeout()并不会在设置的工夫后执行,是因为同步工作的执行超过了定时器指定的工夫,// 因为工作队列的工作只有在主线程上的所有同步工作都执行完后(即调用栈中只剩全局上下文时),才会执行
示例1
<script> console.log('1'); function fn1() { console.log('2'); } fn1(); setTimeout(() => { // macro-task工作 console.log('3'); }, 0) setTimeout(() => { console.log('4') }, 1000) new Promise((resolve) => { // micro-task console.log('5'); // 同步工作,同步工作按调用程序顺次执行 return resolve() }).then(res => console.log('6')) // micro-task先执行</script>执行后果:1 2 5 6 3 4
示例2 - 难度晋升
<script>// 定时器AsetTimeout(() => { console.log('1') // 定时器B setTimeout(() => console.log('2'), 0) // a promise Promise.resolve().then(() => console.log('3'))}, 0)// b promisenew Promise(resolve => { console.log('4') // 定时器C setTimeout(() => { console.log('5') return resolve() }, 0)}).then(() => console.log('6'))// 第一次Event loop// 宏工作 A// 微工作 b// 过程:执行宏工作script整体代码,执行完同步工作,清空micro-task,===> 输入4,宏工作队列:C A// 第二次Event loop// 宏工作 C A// 微工作// 过程:执行A, 宏工作:B C; 微工作:a; 清空micro-task, ===> 输入 1 3,宏工作队列: B C// 第三次Event loop// 宏工作 B C// 微工作// 过程:执行C, 清空micro-task, ===> 输入 5 6, 宏工作队列: B// 第四次Event loop// 宏工作:B// 微工作// 过程: 执行B,清空micro-task, ===> 输入 2// 后果: 4 1 3 5 6 2</script>
示例3 - 坚固学习
<script>// A 定时器setTimeout(() => { console.log('1'); // b promise Promise.resolve().then(() => console.log('2'))}, 0);// B promisePromise.resolve().then(() => { console.log('3'); // a定时器 setTimeout(() => console.log('4'), 0)})// 第一次Event loop// 执行栈 window// 宏工作 A// 微工作 B// 过程:执行宏工作script,清空micro-task, 输入 3,并把 a定时器退出 宏工作队列 a A// 第二次Event loop// 宏工作 a A// 微工作 b// 过程:执行宏工作A, 增加微工作 b, 清空微工作 b// 第三次Event loop// 宏工作 a // 微工作 // 过程:执行宏工作a// 后果:3 1 2 4</script>
nodejs事件循环机制
node事件循环机制1. timers阶段- timers阶段也叫定时器阶段,次要是计时和执行到点的计时器2. pending callbacks阶段- 零碎相干,如tcp谬误3. idea prepare - 筹备工作4. poll阶段(轮询队列)// poll是轮询的意思(1) 如果轮询队列不为空:顺次从轮询队列中取出回调函数并执行,直到轮询队列为空或者达到零碎的最大限度(2) 如果轮询队列为空: - 如果之前设置过setImmediate函数:间接进入下一个阶段check阶段 - 如果之前没有设置过setImmedidate函数:在以后poll阶段期待 - 直到轮询队列增加回调函数,就会4(1)的状况执行 - 如果定时器到点了,也会去下一阶段check阶段5. check阶段- 执行setImmediate函数6. close callbacks 阶段- 执行close事件回调函数留神:process.nextTick()能在任意阶段优先执行
综合案例
nodejs事件循环setImmediate(() => { console.log('setImmediate')}) // 在poll阶段,轮询队列为空时,如果之前设置过setImmediate则间接跳到下一阶段check阶段就执行Immediate函数setTimeout(() => console.log('setTimeout'), 0) // 第一个阶段timer阶段,计时器delay是0,则在第一个阶段就执行process.nextTick(() => console.log('process.nextTick')) // 任意阶段优先执行执行后果:'process.nextTick''setTimeout''setImmediate'
导航
[[深刻01] 执行上下文](https://juejin.im/post/684490...
[[深刻02] 原型链](https://juejin.im/post/684490...
[[深刻03] 继承](https://juejin.im/post/684490...
https://yangbo5207.github.io/...
https://juejin.im/post/684490...
我的语雀:https://www.yuque.com/woowwu/...