进程和线程

  • 进程:一个程序(应用)「例如 饭店」
  • 线程:程序中具体干活的「例如 服务员」

一个进程中可能包含多个线程!!
浏览器中新打开一个页卡,就相当于开辟一个新的“进程”,在这个进程中,包含多个“线程”

浏览器是多线程的

  • GUI渲染线程「渲染HTML/CSS,最后绘制出相应的页面」
  • JS引擎线程「俗称:主线程 渲染和解析JS代码的」
  • HTTP网络线程「从服务器端,基于HTTP网络,获取相应的资源;同源下最多允许开辟 5~7 个HTTP线程」
  • 定时器监听线程「监听定时器是否到时间」
  • 事件监听线程「监听事件是否触发」

但是,JS代码的渲染是单线程的,因为浏览器只分配一个“JS引擎线程”用来渲染解析JS代码!!

所谓的“同步”或者“异步”编程,主要就是由线程多少来决定的!

同步:

只有一个线程,同时只能干一件事情,上一件事情没有做完,此线程空闲不下来,那么后续的事情都做不了

异步:

具备多个线程,可以同时干很多事情

  • 因为JS代码的渲染是单线程的,所以在JS中大部分代码都是“同步”的,例如:循环…
  • 但是因为浏览器是多线程的,所以在JS中还有部分代码是“异步”的,例如:

    「异步宏任务」
  • 定时器

  • requestAnimationFrame
  • ajax/fetch
  • 事件绑定
  • 「异步微任务」
  • Promise

  • Async/Await
  • IntersectionObserver
  • queueMicrotask

虽然JS中有异步的代码,但是和传统的多线程异步操作还不太一样

  • 所有JS代码的执行,都必须交给“主线程”去执行
  • 所借用的浏览器线程,仅仅是帮助我们监听定时器是否到时间、监听事件是否触发…但是最后代码的执行,还是要交给主线程去执行的

    这样的异步编程处理机制,需要一套完善的运作体系 —-> EventLoop 事件循环机制

练习题

  1. setTimeout(() => {
  2. console.log(1)
  3. }, 20)
  4. console.log(2)
  5. setTimeout(() => {
  6. console.log(3)
  7. }, 10)
  8. console.log(4)
  9. for (let i = 0; i < 90000000; i++) {
  10. // do soming
  11. }
  12. console.log(5)
  13. setTimeout(() => {
  14. console.log(6)
  15. }, 8)
  16. console.log(7)
  17. setTimeout(() => {
  18. console.log(8)
  19. }, 15)
  20. console.log(9)

(88X6RGVOWJ%@US87%GK$)L.jpg

定时器是异步操作

  1. // 定时器即便设置等待时间是零,也不是同步代码,绑定的callback也不会立即执行
  2. // 它也是异步的操作,按照EventLoop机制处理!!
  3. setTimeout(() => {
  4. console.log('A')
  5. }, 0)
  6. console.log('B')//-->'B' 'A'

死循环也会导致异步操作不执行

  1. // 在JS中的任何位置都不要出现死循环,即便是在其他的异步操作中
  2. // 不能论是同步还是异步,代码都是交给主线程渲染,如果死循环,则主线程被一直占用,后续所有的事情都无法处理!!
  3. console.log(1)
  4. setTimeout(() => {
  5. console.log(2)
  6. while (1) { }
  7. }, 10)
  8. console.log(3)
  9. setTimeout(() => {
  10. console.log(4)
  11. }, 500)
  12. console.log(5)