浏览器常驻的线程
JS 引擎线程 (解释执行 js 代码、用户输入、网络请求)
GUI 线程 (绘制用户界面、与 js 主线程是互斥的)
HTTP 网络请求线程 (处理用户的 get、post 请求,返回结果后将回调函数推入任务队列)
定时触发器线程 (setInterval、setTimeout 等待时间结束后把执行函数推入任务队列中)
浏览器事件处理线程 (将 click、mouse 等交互事件发生后将这些事件放入事件队列中)
JS 执行机制
JavaScript 是基于单线程运行的,同时又是可以异步执行的,一般来说这种既是单线程又是异步的语言都是基于事件来驱动的,恰好浏览器就给 JavaScript 提供了这么一个环境
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入 Event Table 并注册函数。
当指定的事情完成时,Event Table 会将这个函数移入 Event Queue 。
主线程的执行任务完毕为空,会去 Event Queue 读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的 Event Loop (事件循环)。
同步任务
执行栈------相当于 js 主线程
1 function foo(ot){ 2 function bar(it){ 3 console.log(it); // 先输出20 4 } 5 bar(20); 6 console.log(ot); // 后输出10 7 } 8 foo(10);
0. 代码没有执行的时候,执行栈为空栈
1. foo 函数执行时,创建了一帧,帧中包含了形参、局部变量 (预编译过程) ,把帧压入栈中
2. 执行 foo 函数内代码,执行 bar 函数
3. 创建新帧,同样有形参、局部变量,压入栈中
4. bar 函数执行完毕,弹出栈
5. foo 函数执行完毕,弹出栈
6. 执行栈为空
异步任务
1 $.ajax({ 2 url:'localhost:/js/domo.json', 3 data:{}, 4 success:function(data){ 5 console.log(data); 6 } 7 }); 8 console.log('run');
0. Ajax 进入 Event Table,注册回调函数 success,执行 console.log( 'run' )
1. Ajax 事件完成 http 网络请求线程把任务放入 Event Queue 中
2. 主线程( 调用栈 )读取任务执行 success 函数
关于定时器 setTimeout
js 引擎底层是红黑树,当程序执行时,定时器会将其推送到任务队列中,只有当 js 的同步任务全部执行完毕之后,才会进行时间间隔,执行定时器,基于以上两点,定时器是不准确的