浏览器线程
按照谷歌浏览器来说,其一个 tab 页签是一个进程,每个进程中存在多个线程
进程:资源分配的最小单位
线程:程序执行的最小单位
常见的浏览器线程包括以下几种:
GUI 线程,当需要渲染 html 页面或者重绘页面时,该线程就会执行。
js 线程,用来执行 js,一直等待着任务队列中的任务到来,然后解析 js 脚本,执行代码。一个进程中永远只有一个 js 线程在运行 js 程序。当 js 线程活跃时,会中断 GUI 线程,该线程和 GUI 线程是互斥运行的。
定时器线程,当 setTImeOut 和 setInterval 被调用时,会被专门的定时器线程处理。当计数完成后,其回调函数会被加入任务队列末尾,等待 js 引擎处理
http 网络服务线程,用来处理 http 请求等。当请求完成有回调函数时,会把该回调函数加入任务队列末尾,等待 js 引擎处理。
事件处理线程,demo 中的每一个事件被触发,都会起一个被浏览器事件处理线程处理。当事件被触发时,会把事件函数加入任务队列末尾,等待 js 引擎处理
任务
一般分为同步任务和异步任务,js 主线程直接执行同步任务,异步任务会进入任务队列中,任务队列主要分为两种,即宏任务队列和微任务队列
宏任务
一般的 setTimeOut,setInterval,script 主文件,ajax 请求的回调函数,I/O 操作等都属于宏任务
微任务
一般 premise 的 then 回调,process.nextTikc()等属于微任务
事件循环
在 js 遇到 script,把它放在宏任务队列中。在解析的过程中,遇到同步代码,会顺序执行。遇到异步代码,则判断是宏任务还是微任务,宏任务放在宏任务队列的末尾,微任务放到微任务末尾。
当一个宏任务执行完成后,会立即执行微任务队列中的微任务。微任务中产生的宏任务或微任务,按之前的方式分别放置在对应队列中。只有当前微任务队列中的所有微任务全部执行完成后,才会执行下一个宏任务。
这个循环执行的过程,就是事件循环。当所有任务执行完毕后,js 线程会等待任务队列中任务的到来,一旦有新任务到来,则继续重复以上动作。
例子
1 | new Promise((resolve) => { |
输出:
111,222,333,444,555,666,777