自我理解js执行顺序——附件练习题和自我解析的答案

前言

现在每次文章开篇必前言,今天中午公司前端组发了一道题,当时面试也看过,没总结,导致看到题目知道是js执行顺序,并且包括宏任务,微任务,但是答案确差了很远,因此再次总结一下

js执行顺序

我们知道,js是一条流水线,没有多余的分支,而且是从上往下执行
原理是v8引擎是用来解析js的,因为v8引擎是单线程所以导致js也是单线程的,

此时你会有疑问:但是我们所认识的定时器不是“多线程”吗?实际上定时器是假的‘多线程’。 这个问题留到后面你就知道了

在v8引擎中有主线程任务队列两个,同时执行顺利就是先同后异,先微后宏
当v8引擎解析到异步代码时,比如定时器,就会把异步代码交给相关的模块处理,处理完之后,再交给事件队列中排队,当执行栈有空时,消息队列就把事件交给调用栈执行。

简单理解就是:军人优先
比如在一个打仗的队伍里,有军人和普通人相互穿插着,军人就是同步,普通人就是异步。因为军人优先,所以所有军人会从队伍里出来,排成一队,则这就是主线程,普通人排成一队,则这就是任务队列,当军人依次完成任务不见了,主线程就会空出来,此时普通人中的成年男人(微任务)就站出来,排到主线程中,当成年男人完成任务也依次不见了,那么剩下的人(宏任务)就要占到主线程中。

通过这个故事,估计我们大体可以了解什么是同步,异步,微任务,宏任务,主线程和任务队列。下面通过做题可以加深对js执行顺序有更深的了解。
在做题前,我们先了解一下宏任务,微任务有哪些

微任务

-我所了解的微任务有

  • Promise.then catch finally
  • async…await(他是promise的语法糖)
  • Object.observe
  • MutationObserver

注意:Promise的内容是同步的,他的then catch finally的回调才是异步的

宏任务

-我所了解的宏任务有

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering

练习1

setTimeout(() => console.log(1), 0)
new Promise(res => {
    
    
	console.log(2)
	setTimeout(() => console.log(3), 0)
	res()
}).then(() => console.log(4))
console.log(5)

练习1解析:这个代码是混着的,因此我们从上往下先把军人,男人和剩下的人分开出来

同步 微任务 宏任务
console.log(2) console.log(4) setTimeout(() => console.log(1), 0)
console.log(5) setTimeout(() => console.log(3), 0)

因此我们得出执行顺序就是2.5.4.1.3

练习2

setTimeout(() =>
	 new Promise(res => {
    
    
		console.log(6)
		setTimeout(() => console.log(7), 0)
		res()
	 }).then(() => console.log(8))
, 0)
new Promise(res => {
    
    
	console.log(2)
	setTimeout(() => console.log(3), 0)
	res()
}).then(() => console.log(4))
console.log(5)

练习2解析:

同步 微任务 宏任务
console.log(2) console.log(4) setTimeout(() => new Promise(res => {console.log(6) setTimeout(()=> console.log(7), 0) res()}).then(() => console.log(8)), 0)
console.log(5) setTimeout(() => console.log(3), 0)

我们先执行同步:则前三个我们很容易得出答案:2.5.4
此时我们对于宏任务包含微任务会很懵逼
此时在主线程只剩下宏任务,那么我们把宏任务再接着拆解

同步 微任务 宏任务
console.log(6) console.log(8) setTimeout(() => console.log(3), 0)
- - setTimeout(() => console.log(7), 0)

在这个排队中,我们会觉得3为什么会在7前面,你可以只样子理解,当我们执行到宏任务a1的时候,此时他已经从任务队列出来了,到了主线程中,但是执行的时候,发现他们是一家人,里面有同,微,宏三种,因此我们要把他们拆开,但是你拆开宏就要乖乖排到后面,而不能插队
那么我们很自然的得出答案就是2.5.4.6.8.3.7

练习3

console.log("游戏开始",1);
new Promise( (resolve) => {
    
    
   console.log("promise",2);
   resolve();
})
.then( () => {
    
    
   console.log("then",3);
});
console.log("promise结束",4);
setTimeout( () => {
    
    
   console.log("setTimeout",5);
   new Promise( (resolve) => {
    
    
       console.log("promise",6);
       resolve();
   })
   .then( () => {
    
    
       console.log("then",7);
   });
},0);
new Promise( (resolve) => {
    
    
   console.log(promise,8);
   resolve()
})
.then( () => {
    
    
   console.log(then,9)
   setTimeout( () => {
    
    
       console.log("setTimeout",10);
   },0);
})
console.log("游戏结束",11);

同理,我么接着拆分

同步 微任务 宏任务
console.log(“游戏开始”,1); console.log(“then”,3); console.log(“setTimeout”,5);new Promise( (resolve) => {console.log(“promise”,6);resolve();}) .then( () => {console.log(“then”,7);});
console.log(“promise”,2); console.log(then,9) setTimeout( () => {console.log(“setTimeout”,10); },0); -----
console.log(“promise结束”,4); ----- -----
console.log(promise,8); ----- -----
console.log(“游戏结束”,11); ----- -----

我们可以得出前6个答案:1,2,4,8,11,3

此时我们执行到了

console.log(then,9)
setTimeout( () => {
    
    
   console.log("setTimeout",10);
},0);

接着拆分

同步 微任务 宏任务
console.log(then,9) - console.log(“setTimeout”,5);new Promise( (resolve) => {console.log(“promise”,6);resolve();}) .then( () => {console.log(“then”,7);});
- - setTimeout( () => { console.log(“setTimeout”,10);},0);

同习题2一样,新增的宏任务不能插队
得出接下里答案是 9

此时我们接着拆分宏a1

同步 微任务 宏任务
console.log(“setTimeout”,5); console.log(“then”,7) -
console.log(“promise”,6); - setTimeout( () => { console.log(“setTimeout”,10);},0);

得出答案5.6.710

最后习题3的答案就是1.2.4.8.11.3.9.5.6.7.10

做完题是不是觉得定时器是假的‘多线程’。

猜你喜欢

转载自blog.csdn.net/weixin_43236062/article/details/115004552