单线程定义

    单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。
    单线程就是进程只有一个线程。
    多线程就是进程有多个线程。

Javascript 单线程

    其实这里Javascript的单线程运行机制和上面单线程定义是一个执行流程,它只有一个主线任务,比如:前面有一条河中间只有一根木棍,想要过河只能从一边按顺序走,单个单个的执行,如果从两头一起过河Javascript的单线程就会造成阻塞,这里只是举例了一个简单的解释示例,虽然JavaScript是单线程的且效率太低只能按部就班的一步步走,可是浏览器内部不是单线程的。你的一些I/O操作、定时器的计时和事件监听(click, keydown...)等都是由浏览器提供的其他线程来完成的

任务队列和事件循环

  • 调用栈

       代码在运行过程中,会有一个叫做调用栈的概念。调用栈是一种栈结构,它用来存储计算机程序执行时候其活跃子程序的信息。(比如什么函数正在执行,什么函数正在被这个函数调用等等信息)

    代码示例

       function expale(a) {
           return a+1
       }
       console.log(expale(1))

    上面的例子我们创建了一个简单的函数,然后利用console打印并执行了这个函数,在console这里执行的时候已经形成了一个栈,我们也可以比喻成一个比较大的盒子,console.log(expale(1))就是底部的一个盒子,然后expale(1)会变成另一个盒子落在console.log(expale(1))上面这就形成了栈,其实就是上面所说到的存储计算机程序执行时候其活跃子程序的信息。最后只想说因为它是单线程

  • 任务队列

       宏任务队列:
                   setTimeout
                   setInterval
                   setImmediate
                   I/O 
                   UI rendering (浏览器渲染)
       微任务队列:
                   process.nextTick(下一个事件轮询的时间点上执行)
                   Promise
                   Object.observer
                   MutationObserver(监视 DOM 变动的接口)
             
       console.log('11221121');
       // 微任务
       Promise.resolve().then(() => {
           console.log('p 1');
       });
       
       // 宏任务
       setTimeout(() => {
           console.log('setTimeout');
       }, 0);

    等宏任务执行完(全局执行完)就会开始执行整个微任务队列

  • 事件循环

clipboard.png

    如上图所示stack存储着要执行的任务,下面黄色的onclick函数就是消息队列,一旦有异步响应就会被推入到该队列中。比如:用户的点击事件,setTimeout等等,然后再进入到stack栈中,然后再有任务进入消息队列,再执行这样就形成了事件循环
    
    单线程从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有新的任务,就会等待,直到有新的任务,这就叫任务循环。因为每个任务都由一个事件所触发,所以也叫事件循环。

异步机制

    如果函数是异步的,发出调用之后,马上返回,但是不会马上返回预期结果。调用者不必主动等待,当被调用者得到结果之后会通过回调函数主动通知调用者,上面咱们也简单的介绍了栈和任务队列,以及简单的事件循环,做了一些铺垫

代码

   function send () {
       ajax()...
   }
   send()

上面是一段ajax的一段代码执行,这时候单线程里面已经有这个任务了,当我们执行send()之后这个任务在页面中其实已经完成了,但是我们无法拿到它的结果,在JavaScript中通过回调函数在耗时操作执行完成后把相应的结果信息传递给回调函数,通知执行JavaScript代码的线程执行回调,这也就应上面那句话“不会马上返回预期结果”

浏览器常驻线程

  • 渲染引擎线程:顾名思义,该线程负责页面的渲染
  • JS引擎线程:负责JS的解析和执行
  • 定时触发器线程:处理定时事件,比如setTimeout, setInterval
  • 事件触发线程:处理DOM事件
  • 异步http请求线程:处理http请求

在这里我们要注意js引擎和渲染线程是不能同时进行的,渲染要在js引擎之前

代码

    setTimeout(function(){
        console.log('timer a');
    }, 0)
    
    for(var j = 0; j < 5; j++){
        console.log(j);
    }
    
    setTimeout(function(){
        console.log('timer b');
    }, 0) 
    console.log('click begin');
 

setTimeout的作用是操作者可以设定时间插队,我们可以把它想象成一个会员,有特殊待遇,你可以插队,但是这里的setTimeout(fn, 0)是将函数插入执行队列,等待执行,但是它不会立即执行,不是立即执行,下面的代码就是一个很好的例子 b a

    setTimeout(function() {
        console.log("a")
    }, 0)
    
    console.log("b")
总结
其实JavaScript单线程并不孤单(浏览器的其他线程帮助它),它只是执行栈内的同步任务,执行完之后会再次执行下一个,直到执行完为止,然后栈中无任务事件,它就会等待直到它出现,一直这样的循环下去

参考文章
JavaScript异步机制详解

JavaScript单线程和异步机制

阮老师Event Loop


me_zhazha
294 声望6 粉丝

« 上一篇
原型链
下一篇 »
js 观察者