当前位置: 首页 > Web前端 > JavaScript

[深入04]事件循环

时间:2023-03-27 15:41:59 JavaScript

导航[[深入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]Curried偏函数记忆](https://juejin.im/post/684490...[[深入06]隐式转换与运算符](https://juejin.im/post/684490...【【深入07】浏览器缓存机制(http缓存机制)】(https://juejin.im/post/684490...【[In-深度08]前端安全](https://juejin.im/post/684490...[[深度09]DebounceThrottle](https://juejin.im/post/684490...[[深度10]DebounceThrottle](https://juejin.im/post/684490...[[深入11]前端路由](https://juejin.im/post/684490...[[In-深度12]前端模块化](https://juejin.im/post/684490...[[深入13]观察者模式发布订阅模式双向数据绑定](https://juejin.im/后/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]手写承诺](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-pre-knowledge]AST抽象语法树](https://juejin.im/post/684490...[[Source-webpack02-pre-knowledge]Tapable](https://juejin.im/post/684490...[[源码-webpack03]手写webpack-编译器简单编译过程](https://juejin.im/post/684490...[[源码]ReduxReact-Redux01](https://juejin.im/post/684490...[[源码]axios](https://juejin.im/post/684490...[[源码]vuex](https://juejin.im/post/684490...js单线程为什么js是单线程的?设计js的目的是操作DOM等如果是多线程threaded,两个线程同时对同一个DOM元素进行不同的操作,会产生问题(竞争执行权)进程和线程的区别一个进程可以有多个线程一个线程只能属于一个进程A进程有自己独立的地址空间,一个进程崩溃不会影响其他进程一个线程只是一个进程不同的执行路径,线程有自己的栈和局部变量,但是没有单独的线程之间的地址空间,当一个线程死亡时,整个线程都死亡</font>一些话stackstackheapstackqueuequeuequeuemacro-task:宏任务micro-task:微任务execution-context:执行上下文stackandqueuestack:lastinfirstoutqueue:先进先出同步任务,异步tasksynchronousTask:对于在主线程上排队等待执行的任务,只有在上一个任务执行完后,才会执行后面的任务。异步任务:对于没有进入主线程就进入任务队列的任务,只有“任务队列”通知主线程一个异步任务可以执行,主线程的同步任务执行完后,任务才会进入主线程,在一个线程中执行事件循环。事件循环是唯一的,但是taskqueue可以有多个taskqueue包括:macro-task,和微任务,在新标准中,它们被称为task和jobs宏任务,包括:script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UIrendermicro-task包括:Promise、process.nextTick、MutationObserver(html5新特性)任务队列任务队列分为宏任务(macro-task)和微任务(micro-task),也叫task和jobsinonethread,task队列可以有多个宏任务包括script(整体代码),setTimeout,setInterval,setImmediate,I/O,UIrender等微任务包括Promise,process-nextTick,MutationObserver(html5新特性)任务源和执行任务源:setTimeout/setInterval等教程任务源执行任务:进入任务队列的是任务源分发的执行任务,即回调函数</font>进入任务队列是:任务源分配的执行任务,即回调函数setTimeout立即执行:setTimeout()函数本身就是一个任务dispatcher,会立即执行延时执行:延时执行是setTimeout的第一个参数,是回调函数,会进入macro-taskwindow.setTimeout(function(){console.log('timer')},100)//setTimeout(callback,delay)会立即执行//setTimeout的一个参数会在dalay毫秒后执行,前提是同步任务的执行时间小于delay毫秒//执行setTimeout()时,进入函数调用栈,或者说执行上下文栈,执行完,出栈//和callback回调会在delay毫秒后进入任务队列,等待进入主线程//任务队列:分为宏-任务,微taskindow.setTimeout(function(){console.log('timer')},0)//setTimeout()的第二个参数为0,表示所有同步任务执行完毕后,会尽快执行回调//关于setTimeout,即使主线程为空,其实也达不到0毫秒按照HTML标准,最小事件循环在4毫秒量级!!!事件循环的顺序决定了js代码的执行顺序每一个任务的执行,无论是宏任务还是微任务,都是借助函数调用栈完成的事件循环的顺序:事件循环从宏任务开始,即从脚本整体代码开始,全局执行上下文第一次进入函数调用栈(执行上下文栈),然后然后同步任务按调用顺序进入,同步任务进入主线程,异步任务进入分支线程,定时器/事件等由浏览器相应模块执行(定时器模块,事件处理模块),直到函数调用栈被清空(只剩下global,全局执行上下文一直在栈底),即执行完同步任务,然后执行micro-task中的micro-task任务队列当所有的微任务micro-tasks执行完毕,循环又从macro-task开始macrotask,然后执行完所有的micro-tasks,如此循环下去。每个任务的执行,无论是宏任务还是微任务,都是借助于函数调用栈(executioncontextstack)完成的,即主线程的同步任务执行完毕后,任务队列中的tasksenter主线程执行,即进入函数调用栈分析:(1)stack是执行上下文栈(函数调用栈),最下面是全局执行上下文,最上面是初始化function//注意:函数分为初始化函数和回调函数,所以区分只是为了更好的理解事件循环。(2)比如定时器,js会把定时器的回调和时间交给浏览器(定时器管理模块)单独线程执行,定时器管理模块只是计时,当时间到了起来,将回调函数放入任务队列回调队列,等待进入主线程执行。(3)例如当事件发生时,浏览器的事件处理函数会将回调放入任务队列setTimeout(cb,delay)//setTimeout()执行后进入函数调用栈,outofthestack//cb和dalay进入浏览器的子线程,由浏览器的定时器管理模块执行。延时时间后回调函数放入任务队列//有时setTimeout()没有设置时间后执行,因为同步任务的执行超过了定时器指定的时间,//因为任务在taskqueue只有在主线程上的所有同步任务都执行完后(即调用栈中只剩下全局上下文时)才会执行,才会执行example1executionResult:125634例子2-难度增加示例3-巩固学习