说明:
Javascript是一门非阻塞单线程脚本语言;
浏览器是多进程的,系统给它的进程分配了资源(CPU、内存),打开Chrome
会有一个主进程,每打开一个Tab
页就有一个独立的进程;
JavaScript的任务分为同步任务和异步任务,所有的同步任务都会进入到主执行栈(形成一个执行栈execution context stack),等待任务的回调结果进入一种任务队列(task queue),直到主执行栈的任务执行完毕才会执行任务队列的异步任务,异步任务会塞入主执行栈,异步任务执行完毕后会再次进入下一个循环,整个执行过程,我们称为事件循环过程。任务队列又分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为task与jobs。
macro-task大概包括:
- script(整体代码)
- setTimeout
- setInterval
- setImmediate
- I/O
- UI render
micro-task大概包括:
- process.nextTick
- Promise
- Async/Await(实际就是promise)
- MutationObserver(html5新特性)
整体执行流程图:
async/await执行顺序注意:
输出:script start => async2 end => Promise => script end => promise1 => promise2 => async1 end => setTimeout
分析这段代码:
- 执行代码,输出
script start
。 - 执行async1(),会调用async2(),然后输出
async2 end
,此时将会保留async1函数的上下文,然后跳出async1函数。 - 遇到setTimeout,产生一个宏任务
- 执行Promise,输出
Promise
。遇到then,产生第一个微任务 - 继续执行代码,输出
script end
- 代码逻辑执行完毕(当前宏任务执行完毕),开始执行当前宏任务产生的微任务队列,输出
promise1
,该微任务遇到then,产生一个新的微任务 - 执行产生的微任务,输出
promise2
,当前微任务队列执行完毕。执行权回到async1 - 执行await,实际上会产生一个promise返回,即
let promise_ = newPromise((resolve,reject){ resolve(undefined)})
- 执行完成,执行await后面的语句,输出
async1 end
- 最后,执行下一个宏任务,即执行setTimeout,输出
setTimeout
新版的chrome浏览器中不是如上打印的,因为chrome优化了,await变得更快了,输出为:
而await后面跟的是一个异步函数的调用,比如上面的代码,将代码改成这样:
输出:script start => async2 end => Promise => script end => async1 end => promise1 => promise2 => async1 end setTimeout
未写完,后续待更新...