一道经典的前端口试题,你能一眼写出他们的执行后果吗?
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");
},0);
async1();
new Promise(function (resolve) {console.log("promise1");
resolve();}).then(function () {console.log("promise2");
});
console.log('script end');
首先第一个问题: JavaScript 运行机制是什么?
具体可参考:https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc
总结几点就是:
- JavaScript 语言是单线程的,同一个工夫只能做一件事;
- 遵循事件循环机制,当 JS 解析执行时,会被引擎分为两类工作,同步工作(synchronous)和 异步工作(asynchronous)。对于同步工作来说,会被推到执行栈按程序去执行这些工作。对于异步工作来说,当其能够被执行时,会被放到一个 工作队列(task queue)里期待 JS 引擎去执行。当执行栈中的所有同步工作实现后,JS 引擎才会去工作队列里查看是否有工作存在,并将工作放到执行栈中去执行,执行完了又会去工作队列里查看是否有曾经能够执行的工作。这种循环查看的机制,就叫做事件循环(Event Loop)。对于工作队列,其实是有更细的分类。其被分为 微工作(microtask)队列 & 宏工作(macrotask)队列。
第二个问题:Promise 的原理和运行机制是什么?
古人云:“小人空头支票”,这种“承诺未来会执行”的对象在 JavaScript 中称为 Promise 对象。
Promise 是异步编程的一种解决方案,其实是一个构造函数,本人身上有 all、reject、resolve 这几个办法,原型上有 then、catch 等办法。
参考:https://blog.csdn.net/qq_37860963/article/details/81539118
这里扩大一个问题:什么是异步呢?
同步
就是一件事一件事的执行。只有前一个工作执行结束,能力执行后一个工作。
js 代码只能一行一行的执行,不能在同一时间执行多个 js 代码工作,这就导致如果有一段耗时较长的计算,或者是一个 ajax 申请等 IO 操作,如果没有异步的存在,就会呈现用户长时间期待,并且因为当前任务还未实现,所以这时候所有的其余操作都会无响应,这时候就须要异步工作。
参考:https://blog.csdn.net/li123128/article/details/80650256
Promise 运行程序总结:
- promise 的构造函数是同步执行,promise.then 中的函数是异步执行。
- 构造函数中的 resolve 或 reject 只有第一次执行无效,屡次调用没有任何作用。promise 状态一旦扭转则不能再变。
- promise 的 .then 或者 .catch 能够被调用屡次,但这里 Promise 构造函数只执行一次。或者说 promise 外部状态一经扭转,并且有了一个值,那么后续每次调用 .then 或者 .catch 都会间接拿到该值。
- 如果在一个 then()中没有返回一个新的 promise,则 return 什么下一个 then 就承受什么,如果 then 中没有 return,则默认 return 的是 undefined.
- then()的嵌套会先将外部的 then()执行结束再继续执行内部的 then();
- catch 和 then 的连用,如果每一步都有可能呈现谬误,那么就可能呈现 catch 前面接上 then 的状况。如果在 catch 中也抛出了谬误,则前面的 then 的第一个函数不会执行,因为返回的 promise 状态曾经为 rejected 了
第三个问题:async、await 执行程序?
什么是 Async/Await?
- async/await 是写异步代码的新形式,以前的办法有 回调函数 和Promise。
- async/await 是基于 Promise 实现的,它不能用于一般的回调函数。
- async/await 与 Promise 一样,是非阻塞的。
- async/await 使得异步代码看起来像同步代码,这正是它的魔力所在。
- await 关键字只能用在 aync 定义的函数内。async 函数会隐式地返回一个 promise,该 promise 的 reosolve 值就是函数 return 的值。
执行程序:
应用 async 定义的函数,当它被调用时,它返回的其实是一个 Promise 对象。(当这个 async 函数返回一个值时,Promise 的 resolve 办法会负责传递这个值;当 async 函数抛出异样时,Promise 的 reject 办法也会传递这个异样值。)
await 是一个让出线程的标记。await 前面的函数会先执行一遍,而后就会跳出整个 async 函数来执行前面 js 栈的代码,等本轮事件循环执行完了之后又会跳回到 async 函数中期待 await 前面表达式的返回值,如果返回值为非 promise 则继续执行 async 函数前面的代码,否则将返回的 promise 放入 promise 队列。
参考:https://segmentfault.com/a/1190000011296839
问题四:setTimeout 的执行?
setTimeout 和 Promise 一样也是异步的
宏工作个别包含:整体代码 script,setTimeout,setInterval。
微工作:Promise,process.nextTick
微工作执行优先级高于宏工作,所以 Promise 比 setTimeout 优先执行。
了解了以上 4 个问题,那么这道口试题也就容易了解了
最终后果: