Javascript 执行机制 - 事件循环
事件循环(Event Loop)
所谓的 Event Loop 就是把这些东西串联起来的一种机制,因为这东西各有理解,比如两位前端大牛之间就有分歧。阮一峰:JavaScript 运行机制详解:再谈Event Loop朴灵:朴灵评注我看过他们很多的博客和书籍,对我帮助都很大,我就用自己的看法讲讲我眼中的 Event Loop。
1,所有的任务都被放主线程上运行形成一个执行栈(execution context stack),其中的方法入参变量保存在栈内存中,复杂结构对象被保存在堆内存中;
2,同步任务直接执行并阻塞后续任务等待结束,其中遇到一些异步任务会新开线程去执行该任务(如上面提到的定时器触发线程,异步 http 请求线程等)然后往下执行,异步任务执行完返回结果之后就把回调事件加入到
任务队列(Queue)
;
3,当
执行栈(execution context stack)
所有任务执行完之后,会到任务队列(Queue)
里提取所有的微任务队列(micro tasks)
事件执行完;
4,一次循环结束,GUI 渲染线程接管检查,重新渲染界面;
5,
执行栈(execution context stack)
到宏任务队列(macro tasks)
提取一个事件到执行,接着主线程就一直重复第 3 步;
大概理解就这样子,当然可能会有点偏差,欢迎指正!
特殊的定时器
我在上面线程说过
定时器触发线程:因为 JS 引擎是单线程容易阻塞,所以需要有单独线程为
setTimeout
和setInterval
计时并触发,同样是符合触发条件(记时完毕)被触发时会把对应任务添加到处理队列的尾部等到 JS 引擎空闲时处理;W3C 标准规定时间间隔低于 4ms 被算为 4ms。
里面有一些需要特别注意的地方:1,计时完毕只是把对应任务添加到处理队列,依然要等执行栈空闲才会去提取队列执行,这个概念很重要,切记!即使设置 0 秒也不会立马执行,因为 W3C 标准规定时间间隔低于 4ms 被算为 4ms,具体看浏览器,我个人认为不管怎样始终都会被放置到处理队列等待处理;2,setTimeout 重复执行过程中每次时间误差会影响后续执行时间,而 setInterval 是每次精确时间执行,当然这是指他们把对应任务添加到处理队列的精确性;
但是 setInterval 也有一些问题:
累计效应,如果执行栈阻塞时间足够长以至于队列中已经存在多个 setInterval 的对应任务的情况,执行时间会远低于开发者期望的结果;
部分浏览器(如 Safari 等)滚动过程执行 JS,容易造成卡顿和未知错误;
浏览器最小化显示时 setInterval 会继续执行,但是对应任务会等到浏览器还原再一瞬间全部执行;
评论