每日一问の五:JavaScript 运行机制

每日一问の五:JavaScript 运行机制

一、js为单线程

     js语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那如果同一时间做2件事的话效率是不是能高一些,那为什么不是呢? 嗯...js是单线程与特的用途有关系,作为浏览器脚本语言,js的主要用途是展示页面和用户互动,以及操作dom。我们先假设:如果现在有一个线程在操作dom,又有一个线程在删除dom,那以哪一个为基准呢?

     为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。 

二、js循环机制(任务队列)

        任务队列在同一种类型下,根据队列顺序依次在‘执行栈’中执行,如果有不同类型,执行顺序会按照优先级一次执行。
        任务类型:宏任务和微任务

:

 正如上图所看到的:宏任务的优先级高于微任务,每一个宏任务执行完毕都必须把当前的微任务队列清空,如果队列还存在宏任务,一直循环着。
 这就是js的循环机制。

这里拓展一下什么是执行栈:

   在js中函数一旦过多,就有多个函数执行上下文,每次调用函数创建一个新的执行上下文,那是怎么管理创建的那么多的执行上下文?
   js引擎创建了执行上下文栈来管理执行上下文,可以啊执行上下文栈认为一个存储数调用的栈街都,遵循先进后出的原则。执行栈:call stack一种结构,放的是函数的执行环境,每一次函数执行之前,他的所有内容全部会放到执行栈,函数调用之前,会创建执行环境,放到执行栈当中,函数调用完成,销毁执行环境。

:

    就像我们上图一样:在执行栈中必须遵守先进后出,后进先出,自下而上的顺序。

        js执行在单线程上,所有代码都是排队执行。
        一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。
        每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行完成之后,当前函数的执行上下文出栈,并等待垃圾回收。
        浏览器的js执行殷情总是访问栈顶的执行上下文。

三、任务队列

    单线程意味着所有的任务都需要排队,前一个结束,才会执行后一个任务。如果前一个任务耗时很长,下一个任务就不得不等着。
    如果排队是因为计算量大,cpu忙不过来,也罢了,但是有时候IO设备(输入输出设备)很慢我们的代码可能会是ajax调取接口比较费时,这时候不得不等到后台返回值才能执行下个任务。js设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO(输入输出设备)返回了结果,再回头,把挂起来的任务继续执行下。
    于是:所有任务可以分成两种,一种同步,一种异步。同步是指:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步是指:不进入主线程、而进入‘任务队列’得任务,只有'任务队列'通知主线程,某个异步任务可以执行了,该任务才会进入主线程。 

执行步骤:

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

四、事件和回调函数

‘任务队列’是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在‘任务队列’中添加一个事件,表示相关的异步任务可以进入“执行栈”了。主线程读取“任务队列”,就是读取里面有哪些事件。
任务队列中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击,页面滚动)。只要指定过回调函数,这些事件发生时就会进入任务队列,等待主线程读取。所谓“回调函数”,就是那些会被主线程挂起来的代码,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,任务队列上第一位的事件就自动进入主线程。但是,js中又有定时器的功能,主线程首先要检查一下执行时间,某些事件只有到了规定的事件,才才能返回主线程。

五、定时器

除了放置异步任务的事件,任务队列还可以放置定时事件,比如定时器(也就是定时执行的代码)。
注意:定时器只是将时间插入了任务队列,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。总之:定时器的含义是:指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
讨论数量: 0

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!