这是本人的理解,并且Google browser断点实践的,不同浏览器可能存在差异。章末附带外文视频地址。
JS特点
javascript一门单线程的非阻塞的脚本语言。当用户进行点击元素,又进行元素移除,这样就会导致哪个事件的优先级不知道,所以JS必须是单线程的。为了协调事件,用户交互,脚本,UI渲染,和网络处理,Event Loop可以防止主线程阻塞。在某些花费时间较长的事件,浏览器会将它们挂起(pending),事件等待被执行,事件循环是通过任务队列实现的。
one thread == one callback == one thing at a time.
Event Loop
- Browing Context
- Worker 两者是独立的,有各自的线程环境。
栈(Stack)
栈是一种遵循后进先出(LIFO)的数据集合,新添加或待删除的元素都保存在栈的末尾,称作栈顶,另一端称作栈底。在栈里,新元素都靠近栈顶,旧元素都靠近栈底
队列(Queue)
队列是一种遵循先进先出(FIFO)的数据集合,新的条目会被加到队列的末尾,旧的条目会从队列的头部被移出。
微任务与任务
- 任务task:script(整体代码)、setTimeout、setInterval、I/O(输入输出设备)、UI交互事件,setImmediate(Node.js环境),webAPI callback()等
- 微任务:Promise、MutationObserver、process.nextTick(Node.js环境)
JS执行规则
可以这样理解,有两个队列—— 执行队列(同步任务synchronous)、事件队列(异步任务asynchronous),存放所有着JS执行的任务(ajax、点击事件、UI渲染等、promise.then)。
- 执行队列存放所有同步代码的任务
- 事件队列存放所有异步代码的宏任务
- 微任务处于两个队列之间
运行Js代码,从上往下执行代码,同步代码,依次执行,遇到异步代码,则根据其任务类型,添加到相应的对应队列,宏任务放入事件队列,微任务放于执行队列之后(但是会是某个事件循环的最后),事件队列(任务)之前。这个处理事件过程是不断循环的,只要主线程空了,就会去读取"任务队列"并且执行。
demo
复制代码
总结任务
- 任务(tasks)按循序执行,浏览器或许在一边执行任务(tasks)一边更新渲染
- 微任务(microtasks)也是按顺序执行
- 在每一次回调之后执行,只要没有其他js正在执行
- 在每一次任务之后
- 当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。