• JavaScript 异步操作 setTimeout,promise,async await


    setTimeout、promise、async await的实现及执行顺序

    javascript Microtasks 微任务 javascript microtask 宏任务

    javascript Microtasks 微任务
    microtask async/await 和 Promise 实现延迟执行,并在每个 task 结束时执行。在每一个事件循环之前,microtask 队列总是被清空(执行)。

    • process.nextTick
    • promise
    • Object.observe (废弃)
    • MutationObserver

    javascript Macrotasks 宏任务
    macrotasks 用于处理 I/O 和计时器等事件,每次执行一个

    • setTimeout
    • setImmediate
    • setInterval
    • I/O
    • UI 渲染

    javascript event loop

    JS主线程不断的循环往复的从任务队列中读取任务,执行任务,其中运行机制称为事件循环(event loop)。

    1、每一个 event loop 都有一个 microtask queue
    2、每个 event loop 会有一个或多个macrotask queue ( 也可以称为task queue )
    3、一个任务 task 可以放入 macrotask queue 也可以放入 microtask queue中
    4、每一次event loop,会首先执行 microtask queue, 执行完成后,会提取 macrotask queue 的一个任务加入 microtask queue, 接着继续执行microtask queue,依次执行下去直至所有任务执行结束。

    JS的异步运行机制

    JS 主线程拥有一个 执行栈(同步任务) 和 一个 任务队列(microtasks queue),主线程会依次执行代码,

    • 当遇到函数(同步)时,会先将函数入栈,函数运行结束后再将该函数出栈;
    • 当遇到 task 任务(异步)时,这些 task 会返回一个值,让主线程不在此阻塞,使主线程继续执行下去,而真正的 task 任务将交给 浏览器内核 执行,浏览器内核执行结束后,会将该任务事先定义好的回调函数加入相应的任务队列(microtasks queue/ macrotasks queue)中。
    • 当JS主线程清空执行栈之后,会按先入先出的顺序读取microtasks queue中的回调函数,并将该函数入栈,继续运行执行栈,直到清空执行栈,再去读取任务队列。
    • 当microtasks queue中的任务执行完成后,会提取 macrotask queue 的一个任务加入 microtask queue, 接着继续执行microtask queue,依次执行下去直至所有任务执行结束。
    // 今日头条面试题
    async function async1() {
        console.log('async1 start')
        await async2()
        console.log('async1 end')
    }
    async function async2() {
        console.log('async2')
    }
    console.log('script start')
    setTimeout(function () {
        console.log('settimeout')
    })
    async1()
    new Promise(function (resolve) {
        console.log('promise1')
        resolve()
    }).then(function () {
        console.log('promise2')
    })
    console.log('script end')
    

    答案

    script start
    async1 start
    async2
    promise1
    script end
    async1 end
    promise2
    settimeout
    

    async await、Promise、setTimeout

    Promise本身是同步的立即执行函数, 当在 executor 中执行 resolve 或者 reject 的时候, 此时是异步操作, 会先执行 then/catch 等,当主栈完成后,才会去调用 resolve/reject 中存放的方法执行,打印 p 的时候,是打印的返回结果,一个 Promise 实例

    console.log('script start')
    let promise1 = new Promise(function (resolve) {
        console.log('promise1')
        resolve()
        console.log('promise1 end')
    }).then(function () {
        console.log('promise2')
    })
    setTimeout(function(){
        console.log('settimeout')
    })
    console.log('script end')
    // 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
    

    当JS主线程执行到Promise对象时,

    • promise1.then() 的回调就是一个 task
      • promise1 是 resolved 或 rejected :那这个 task 就会放入当前事件循环回合的 microtask queue
      • promise1 是 pending:这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中
    • setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况

    async await

    async function async1(){
       console.log('async1 start');
        await async2();
        console.log('async1 end')
    }
    async function async2(){
        console.log('async2')
    }
    
    console.log('script start');
    async1();
    console.log('script end')
    
    // 输出顺序:script start->async1 start->async2->script end->async1 end
    

    async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。

  • 相关阅读:
    基于bootstrap实现收缩导航条
    js判断打开网站页面是PC端还是手机端
    vs2015调试sqlserver 存储过程
    C#计算当前日是第几周
    C#计算一年有多少周
    tcpdump命令的使用
    keepalived配置
    正则匹配中文
    git merge 和 git rebase详解
    systemd和sysv服务管理和配置
  • 原文地址:https://www.cnblogs.com/boyGdm/p/16241259.html
Copyright © 2020-2023  润新知