美文网首页
JS的单线程和异步

JS的单线程和异步

作者: 名字一定要够长才可爱 | 来源:发表于2019-04-03 23:01 被阅读0次

    简述

    • JavaScript引擎是单线程运行的,浏览器无论在什么时候都有且只有一个线程在运行JavaScript程序,JavaScript本身不可以异步
    • 可执行异步操作的原因: JS的宿主环境(eg: 浏览器, Node)是多线程的,宿主环境通过某种方式(事件驱动)使得JS具有异步的属性

    JS触发异步原理

    1. JS引入异步的原因

    JS是单线程语言,浏览器只分配给JS一个主线程,用来执行任务(函数), 但一次只能执行一个任务,这些任务形成一个任务队列排队等候执行。但是前端的很多任务都是非常耗时的,比如http请求、定时器、事件监听等。如果让他们都按照同步原理顺序执行,那么执行效率会非常低,甚至导致页面的假死。

    2. 浏览器模型

    浏览器模型
    • 用户界面(User Interface): 包括地址栏、前进/后退按钮、书签菜单等
    • 浏览器引擎 (Browser engine):在用户界面和呈现引擎之间传送指令
    • 呈现引擎 (Rendering engine):又称渲染引擎,也被称为浏览器内核,在线程方面又称为UI线程
    • 网络 (Networking):用于网络调用,比如 HTTP 请求
    • 用户界面后端 :用于绘制基本的窗口小部件,UI线程和JS共用一个线程
    • JavaScript解释器 (Javascript Interpreter):用于解析和执行 JavaScript 代码
    • 数据存储 (Data Persistence):这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie

    3. 浏览器对JS异步的支持

    浏览器内核允许多个线程异步执行,这些线程在内核控制下相互配合以保持同步。

    三个常驻线程:

    a). JavaScript引擎线程
    b). 页面渲染线程
    c). 浏览器事件触发线程

    执行完就终止的线程

    a). HTTP请求线程等
    b). 定时触发器线程

    4. 任务队列

    顾名思义: 排着任务的队列。所谓任务就是webAPIs(浏览器为异步任务单独开辟的线程统一称为webAPIs)返回的一个个通知,让JS主线程在读取任务队列的时候得知这个异步任务已经完成,下一步该执行这个任务的回调函数了。主线程拥有多个任务队列,不同的任务队列用来排列来自不同任务源的任务。

    • 任务源: 像setTimeout / Promise / DOM 事件等都是任务源。来自同类任务源的任务我们称它是同源的, 比如setTimeout和setInterval就是同源的。

    5. 事件循环(event loop)

    事件循环(event loop)

    由三大模块组成: 函数调用栈、webAPIs、任务队列

    执行过程:

    1.主线程在遇到ajax或者setTimeout 这种异步操作时会交给浏览器的webAPIs,然后继续执行后面的代码,直到执行栈为空。

    1. 浏览器会在不确定的时间将完成的任务返回,排到相应的任务队列后。
    2. 执行栈为空时,主线程会到任务队列中去取任务,这些任务会告诉下一步应该执行那些回调函数。任务队列是具有优先级的,按照优先级顺序决定访问的先后循序。而优先级在不同的环境中又有所不同,不能一概而论。
    3. 每访问一个队列,执行栈会执行完这个任务队列的的所有代码,然后再取下一个任务队列需要执行的任务代码。如果在执行中遇到了属于当前任务的异步队列时,此次任务的返回不会排到当前的任务队列之后,因为这属于两次单独的事件循环,会被区分开来。
      就这样循环执行,直到三大块全为空,称为事件循环

    6. AJAX请求是否异步

    ajax请求内容的时候是异步的,当请求完成后,会触发请求完成的事件,然后把回调函数放到任务队列中,等到主线程执行该回调函数时还是单线程的。

    7. 界面渲染线程是单独开辟的线程,是不是DOM一变化,界面就立刻重新渲染?

    答案: 不是。
    如果DOM一变化界面就重新渲染,效率必然很低,所以浏览器的机制规定界面渲染线程和主线程是互斥的,主线程执行任务时,浏览器渲染线程处于挂起状态。

    相关文章

      网友评论

          本文标题:JS的单线程和异步

          本文链接:https://www.haomeiwen.com/subject/dultiqtx.html