• JavaScript 的运行机制


    前言

    作为一个前端er,最基本的要求也得知道js的运行机制叭。由于js是单线程的,所以js是按顺序执行的。

    console.log('1')
    console.log('2')
    输出:1,2。果然是按顺序执行的。本文结束。
    

    来点复杂的。

        setTimeout(function () {
          console.log('1')
        })
        new Promise((resolve) => {
          console.log('2')
          resolve()
        }).then(() => {
          console.log('3')
        })
        console.log('4')
    输出:2,4,3,1。这个是为啥子嘞。
    

    从 js 单线程说起

    js是一门单线程的语言,设计之初,是在浏览器中运行的,方便处理DOM树的。如果是多线程的话,一个线程删除DOM,一个线程修改DOM,这样就会出现问题。HTML5引入了web workers,使js能够创建多个线程,是为了防止大量的数据计算阻塞UI渲染,但这些线程都是受主线程控制的,所以js在本质上还是单线程的。

    表面很难的event loop

    js 是单线程的,所以一次只能执行一个任务,当一个任务需要很长时间时,主线程一直等待任务的执行完成,在执行下个任务是很浪费资源的。
    比如,我们吃泡面时候,先烧水,在等待水烧开的时候,我们可以把泡面打开,作料放好,等水开了,直接泡就好。那个吃干脆面的走开。
    所以,js中任务就被分成两种,一种是同步任务,一种是异步任务。执行步骤如下图所示:

    • 1、所有同步任务都在主线程上执行,形成一个执行栈。
    • 2、主线程之外,有个任务队列,存放异步的任务。
    • 3、主线程任务执行完后,会去任务队列中查找异步任务,将其放到执行栈中执行。
    • 4、主线程不断重复上面三步,这也就是常说的事件循环。

    宏任务和微任务

    为了更精细的区分任务,js中可以将异步任务划分为宏任务和微任务。

    • 1、js代码在执行时,首先执行js同步任务,异步任务会放入任务队列中。
    • 2、同步任务执行完后,会去查找有没有微任务可以执行,然后执行所有微任务。第一次事件循环结束。
    • 3、然后进入第二次事件循环,此时,任务队列中的第一个宏任务,将变成同步任务,被首先执行。
    • 4、不断重复1、2、3,以此循环下去,直到所有任务全部执行完成。
    常见的宏任务:

    setTimeoutsetIntervalMessageChannelpostMessagesetImmediate等等。

    常见的微任务:

    promise.thenMutationObsever等等。
    看下这段代码:

        setTimeout(function () {
          console.log('1')
        })
        new Promise((resolve) => {
          console.log('2')
          resolve()
        }).then(() => {
          console.log('3')
        })
        console.log('4')
        
    
    • 首先执行setTimeout,进入任务队列,注册成宏任务。
    • Promise,直接执行,输出:2,然后promise.then,进入任务队列,注册成微任务。
    • 然后遇到console.log('4'),直接输出:4。
    • 同步任务执行完,从任务队列中找出要执行的微任务,输出:3,第一次事件循环结束。
    • 第二次事件循环从宏任务开始,输出:1。
      下面我们看个更复杂的例子:
        console.log('1');
        setTimeout(function () {
          console.log('2');
          new Promise(function (resolve) {
            console.log('3');
            resolve();
          }).then(function () {
            console.log('4')
          })
        })
        new Promise(function (resolve) {
          console.log('5');
          resolve();
        }).then(function () {
          console.log('6')
        })
    
        setTimeout(function () {
          console.log('7');
          new Promise(function (resolve) {
            console.log('8');
            resolve();
          }).then(function () {
            console.log('9')
          })
        })
        console.log('10')
    
    
    • 首先输出:1,然后注册宏任务setTimeout1。然后输出5,注册微任务promise1,然后注册宏任务setTimeout2,然后输出10。注册了微任务promise1,宏任务setTimeout1、setTimeout2
    • 同步任务执行完后,我们发现有微任务promise1在任务队列中,所以微任务promise1进入主线程,执行微任务promise1,输出:6,第一次事件循环结束,输出了1 5 10 6
    • 随后宏任务setTimeout1进入主线程,执行宏任务setTimeout1,输出:2 3,注册微任务promise2
    • 宏任务setTimeout1执行完后,我们发现有微任务promise2在任务队列中,所以微任务promise2进入主线程,执行微任务promise2,输出:4
    • 随后宏任务setTimeout2进入主线程,输出:7 8,注册微任务promise3
    • 最后微任务promise3进入主线程,输出:9
  • 相关阅读:
    虚拟用户图分析
    概要图分析
    服务器资源监控视图
    场景监控之基本信息
    controller场景设计
    ip欺骗
    面试准备
    性能测试
    (一)总结
    bug的描述
  • 原文地址:https://www.cnblogs.com/yangrenmu/p/11073959.html
Copyright © 2020-2023  润新知