笔者大三,前端,期待实习机会,以下是在自己准备面试过程中的一点心得。
如果有错误请多指出。
在js中,程序的一部分现在运行,而另一部分在将来运行,现在和将来之间有段时间间隙。
如何处理这段间隙,如何处理程序的当下运行与未来运行部分是异步编程的核心。
JavaScript引擎运行于宿主环境中,这里简单理解为浏览器,js主线程负责执行代码,浏览器中还有很多线程负责js代码执行调度。
浏览器提供了一种机制来处理代码中多个代码块的执行,且执行每块时调用JavaScript引擎,(js是由JavaScript引擎执行的),这种机制叫事件循环。
接下来需要分清楚两个队列
事件循环队列:存放宏任务
任务队列(job queue):存放微任务
接下来借用别人的宏微任务定义:
宏任务(macrotask)::
script(整体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)
微任务(microtask):
Promise、 MutaionObserver、process.nextTick(Node.js环境)
看过不少八股博客文,里面都在纠结宏任务微任务优先级之分,笔者自认为没有必要,是片面的理解,想深入理解就不要纠结优先级。
然后对JavaScript引擎执行补充一些知识:
JavaScript引擎执行,维护一个唯一主执行栈,主执行栈真正执行Js代码**。**
下面我对《你所不知道的JavaScript》中关于事件循环机制表述的代码做一些添加,然后呈现给读者。
var eventQueue = [];//事件循环队列
var jobQueue = [];//任务队列
let event, job;
while (true) { //while 中的一轮代码叫做一次tick
//Event Loop(事件循环)中,每一次循环称为 tick
if (eventQueue.length > 0) {
event = eventQueue.shift();
try {
event(); //从事件队列拿到主执行栈执行
if (event在执行过程中产生宏任务) {
eventQueue.push(新的宏任务)
}
if (event在执行过程中产生微任务) {
jobQueue.push(新的微任务)
}
} catch (err) {
reportErr(err); //报告错误
}
}
while (jobQueue.length > 0) {
job = jobQueue.shift();
try {
job(); //从任务队列拿到主执行栈执行
if (job在执行过程中产生宏任务) {
eventQueue.push(新的宏任务)
}
if (job在执行过程中产生微任务) {
jobQueue.push(新的微任务)
}
} catch (err) {
reportErr(err); //报告错误
}
}
}
请仔细阅读代码,接下来是对代码内容的总结说明:
while 中的一轮代码叫做一次tick就是Event Loop(事件循环)中的每一次循环。
宏任务(macrotask)中有个script(整体代码),笔者之前不理解,但现在明白并且说说自己的理解**:
**JavaScript引擎执行栈 选择 任务队列队头 的宏任务就是是script
**整体代码
**所以同步代码一定比异步代码先执行(这句话我目前坚信不疑)。
事件循环执行顺序 宏任务一个-微任务一堆-宏任务一个-微任务一堆
宏微任务执行时也会继续产生一些宏微任务,
譬如
async function fn() {
let a = await Promise.resolve('async1');
console.log(a);
setTimeout(function() { console.log("wuhu in async") }, 0);
let b = await Promise.resolve('async2');
console.log(b);
let c = await Promise.resolve('async3');
console.log(c);
}
在执行微任务时产生了一个 setTimeOut宏任务,那就把这个宏任务入事件循环队列末尾即可。
笔者自己写了个测试demo,给大家练习
async function fn() {
let a = await Promise.resolve('async1');
console.log(a);
setTimeout(function() { console.log("wuhu in async") }, 0);
let b = await Promise.resolve('async2') ;
console.log(b);
let c = await Promise.resolve('async3')
console.log(c);
}
console.log("同步");
console.log("同步");
console.log("同步");
new Promise(function(resolve, reject) {
console.log("wuhu in promise") //Promise构造器里面的代码会立即执行
resolve("promise fulfiiled");})
.then((data) => { console.log(data); })
console.log("同步");
console.log("同步");
console.log("同步");
console.log("同步");
fn();
console.log("同步");
setTimeout(function() { console.log("wuhu1") }, 0);
console.log("同步");
console.log("同步");
setTimeout(function() { console.log("wuhu2") }, 0)
console.log("同步");
console.log("同步");
console.log("同步");
// VM63:11 同步
// VM63:12 同步
// VM63:13 同步
// VM63:15 wuhu in promise
// VM63:19 同步
// VM63:20 同步
// VM63:21 同步
// VM63:22 同步
// VM63:24 同步
// VM63:26 同步
// VM63:27 同步
// VM63:29 同步
// VM63:30 同步
// VM63:31 同步
// VM63:17 promise fulfiiled
// VM63:3 async1
// VM63:6 async2
// VM63:8 async3
// VM63:25 wuhu1
// VM63:28 wuhu2
// VM63:4 wuhu in async