最近面试中碰到了一道对于 JS 执行程序的题目,题目比拟根底,然而如果对于 JS 不熟的话,还是容易答不上来。再次记录和剖析此次面试题,心愿对大家有所帮忙。
async function async1() {console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {console.log("async2");
}
console.log("js start");
setTimeout(function () {console.log("timeout");
}, 0);
async1();
new Promise(function (resolve) {console.log("promise");
resolve();}).then(function () {console.log("then");
});
console.log("js end");
话不多说,先上后果
// 控制台输入后果
"js start"
"async1 start"
"async2"
"promise"
"js end"
"async1 end"
"then"
"timeout"
宏工作 微工作
如果看官是个老手的话,看到下面的输入后果,必定一脸懵逼的,然而没关系,看完这篇文章您就懂了。想齐全明确下面这道题目,还须要理解 JS 的两个概念,没错,就是宏工作和微工作。
首先看官必定晓得 JS 是单线程,实现异步的办法就是定时器和 es6+ 呈现的 promise/async 等,那么当初问题来了,既然 es6 呈现的新的异步形式,那么和之前的定时器相比,那个异步先执行呢?
宏工作
(macro)task,能够了解为每段代码都是一个宏工作,没错 JS 的主程序也是宏工作。同时两个定时器异步的局部也是宏工作。
微工作
microtask,能够了解是在以后 task 执行完结后立刻执行的工作。也就是在主程序执行实现之后立刻执行的局部。es6+ 呈现的 promise,async 都是微工作。在这里要记住一句话,微工作的优先级是高于宏工作的。
程序执行程序
1、主程序
因为 js 是单线程的,同一时间只能有一段代码在执行,所以首先执行的就是 JS 的主程序。之前说主程序是宏工作,微工作优先级又比宏工作高,那为什么还先执行主程序这个宏工作呢?
这是因为:没有主程序去构建微工作,微工作又怎么会呈现呢,没有微工作的呈现,当然就去找到主程序这个宏工作了,所以优先级的说法没有谬误。
2、查看是否有异步工作
当上一个工作执行实现之后,程序会去检索是否有微工作,须要执行,如果有,就会先执行微工作。没有微工作但有宏工作,执行宏工作。没有工作,代码不在执行。
3、微工作
微工作代码执行,和失常的 JS 代码执行没有区别,从上往下编译执行!!!执行实现之后,会跳回到第二步。
4、宏工作
宏工作代码执行,和失常的 JS 代码执行没有区别,从上往下编译执行!!!执行实现之后,会跳回到第二步。
解答题目
大家在做此类题目时,也能够像我一样,在一旁记录一个宏工作库、微工作库,依照下面的程序一步一步来,准没错!!!
1、主程序 – async async1
程序申明异步 async 异步函数 async1,当一个函数未调用时,函数内容的代码是不会编译执行的,所以第一步并没有输入内容。
微工作:空
宏工作:空
2、主程序 – async async2
这里同样也只是定义 async 函数 async2,所以这一步也没有输入内容
微工作:空
宏工作:空
3、主程序 – console.log
程序执行到了 console.log,不存在异步,所以间接执行,控制台输入“js start”。
微工作:空
宏工作:空
4、主程序 – setTimeout
程序终于来到了第一个异步局部 setTimeout,这个单次定时器的定时为 0s, 意思为立刻执行,然而因为他是异步的,所以他并不会立刻执行,而是等到所有的主程序和排在他之前的异步工作执行实现之后才会执行。这里会把他增加到宏工作队列。
微工作:空
宏工作:setTimeout
5、主程序 – async1()
程序执行到了 async1 的函数调用,不存在异步,所以程序会去编译并执行 async1 外部局部。
微工作:空
宏工作:setTimeout
5.1、async1 – console.log
async 异步函数是这样的,函数被调用时,程序会失常立刻执行,然而当碰到 await 关键词时,await 下一行的语句会作为微工作退出到微工作队列中,await 前面跟着的局部也是会立刻执行的。因而这个 console.log 会立刻执行,控制台输入“async1 start”
微工作:空
宏工作:setTimeout
5.2、async1 – await async2()
await 语句前面的内容会立刻执行,下一行和之后的内容会退出到微工作队列,所以又进入到 async2 外面,并在微工作队列退出一个微工作。参考:前端进阶面试题具体解答
微工作:async1
宏工作:setTimeout
5.2.1、async2 – console.log
console.log 是立刻执行的,没有异步局部,所以管制台上输入“async2”。至此,async1 外面的同步内容执行实现了。
微工作:async1
宏工作:setTimeout
6、主程序 – Promise
promise 的异步是这样的,在构建实例时传入函数的内容,是立刻编译执行的,前面的 then 会退出到微工作队列。
微工作:async1
宏工作:setTimeout
6.1、Promise – console.log
console.log 立刻执行,没有异步局部。控制台输入“primise”。
微工作:async1
宏工作:setTimeout
6.2、Promise – resolve
resolve 立刻执行,然而前面的 then 退出微工作队列。
微工作:async1 Promise-then
宏工作:setTimeout
7、主程序 – console.log
console.log 立刻执行,没有异步局部。控制台输入“js end”。至此,主程序曾经执行实现,接下来会执行上述的第二步。
微工作:async1 Promise-then
宏工作:setTimeout
8、微工作 async1 – console.log
监测到有微工作,执行微工作。console.log 立刻执行,没有异步局部。控制台输入“async1 end”。同时删除微工作队列中对应的工作,再次回到第二步。
微工作:Promise-then
宏工作:setTimeout
9、微工作 Promise-then – console.log
监测到有微工作,执行微工作。console.log 立刻执行,没有异步局部。控制台输入“then”。同时删除微工作队列中对应的工作,再次回到第二步。
微工作:空
宏工作:setTimeout
8 和 9 两步,在不同的浏览器版本可能执行的程序并不相同,所以不用纠结这两部前后程序问题。
10、宏工作 setTimeout – console.log
监测到没有微工作,执行宏工作队列。console.log 立刻执行,没有异步局部。控制台输入“timeout”。同时删除宏工作队列中对应的工作,再次回到第二步。
微工作:空
宏工作:空
11、执行完结
检测到工作队列都已执行实现,代码执行完结。
总结
至此、面试题就曾经解说实现了,内容比拟长,然而也比拟细,各位碰到相似题目时,能够依照我的办法去做一下,根本不会再出错了。