js 单线程和它的异步执行机制

单线程定义

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

Javascript 单线程

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

任务队列和事件循环

  • 调用栈html

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

    代码示例ajax

    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代码的线程执行回调,这也就应上面那句话“不会立刻返回预期结果”oop

浏览器常驻线程

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

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

代码

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异步机制详解code

JavaScript单线程和异步机制

阮老师Event Loop

相关文章
相关标签/搜索