START
- 番茄我又又又来写点啥啦。
- 今天朋友去找工作,面试之后把面试题给我看了一下,叫我做做看。当我做到有关js代码执行顺序的题目时候,对答案的时候,发现我做错了。和朋友讨论了一下,总觉得,还是要自己深入的了解一下这方面的知识,免得下次我去面试的时候,还会做错,或者说做不来。
- 所以这篇文章就当记录今天的所思所感吧,希望会有收获。
相关文章
- 在进入我的正文之前,一篇文章,写的很棒,很好。所以放在开头,放在前面。
- https://juejin.im/post/6844903512845860872#heading-10
- 本文很多地方借鉴了这篇文章,在此说明,我写这篇文章,只是为了个人记录,侵权删。
面试题
- 第一:先展示一下朋友遇到的面试题
console.log('start')
setTimeout(()=>{
console.log('timeout')
},0)
new Promise((resolve,reject)=>{
resolve()
console.log('resolve')
}).then(()=>{
console.log('then')
})
console.log('end')
- 答案
start
resolve
end
then
timeout
- 不知道你们做这道题会不会和我一样,看到答案,并不理解,别慌,看完这篇文章就会做了。
同步异步
-
首先很重要必须要知道的一点JavaScript是单线程的
- 单线程也就是说,事情必须一件一件的做完,先等最前面的事情做完,才能做后续的任务
- 那这样,必然导致,如果前面的事情很复杂很缓慢很耗时,那后续的事情不是都做不了。
-
所以就有了:
- 同步任务
- 异步任务
-
同步异步有什么区别呢?
-
代码执行顺序不同
-
怎么不同?
- js异步同步运行流程.jpg
-
-
上代码,简单快速的理解一下
setTimeout(() => { console.log('我是定时器的输出') }, 1000) console.log('我是懒番茄')
-
结果
//我是懒番茄 //我是定时器的输出
首先,定时器异步的,按照js从上到下运行机制,一开始运行定时器,因为是异步的,所以就会将定时器中的函数放入Event Table(简单来看就是一个容器)中
然后继续向下执行,运行到`console.log('我是懒番茄')`,同步任务就放到主线程中运行,所以先打印我是懒番茄
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
过了一秒定时器中的代码运行完成了,就会将函数移入到Event Queue(简单来说,也可以看做一个容器)
定时器中的函数进入主线程开始运行,输出 `我是定时器的输出`
-
总结:
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。 当指定的事情完成时,Event Table会将这个函数移入Event Queue。 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
setTimeout
-
记住,定时器是异步的
-
对于
setTimeout(fn,ms)
来说,过ms
秒,fn
会进入Event Queue。- 参数解释:
-
fn
必需。要调用一个代码串,也可以是一个函数。 -
ms
可选。执行或调用 code/function 需要等待的时间,以毫秒计。默认为 0。(不写默认为0) - 关于
setTimeout
要补充的是,即便主线程为空,fn
等待时间,0毫秒实际上也是达不到的。根据HTML的标准,最低是4毫秒。有兴趣的同学可以自行了解。
-
上述有使用案例,就不详细叙述了。
setInterval
- 和setTimeout类似,但是要注意一点:
- 对于
setInterval(fn,ms)
来说,不是每过ms
秒会执行一次fn
,而是每过ms
秒,会有fn
进入Event Queue。
Promise与process.nextTick(callback)
-
process.nextTick(callback)
类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数。 - Promise这里就不详细解释了
- 后续有时间一定出两篇单独写着两个的文章,网上也有很多可以百度一下,后续补充。
宏任务 微任务
-
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
-
micro-task(微任务): Promise.prototype.then ,process.nextTick (new Promise是同步的)
-
首先请务必记住宏任务,微任务的区分
事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务
通俗点的话来说
script整个可以看成一个宏任务,首先执行的就是script这个整体,遇见同步的就直接放到主线程执行,遇见微任务就放入到本次事件循环宏任务的微任务队列中,遇见宏任务就挂起,满足执行条件后就放入到宏任务队列,script这个宏任务执行完毕后就开始执行本次宏任务中的微任务队列,微任务队列内容执行完毕后就相当于第一次事件循环结束。下面开始把满足条件的宏任务队列拿出来一个(就好像script一样)继续执行。所以叫做事件循环,因为一直在循环。
- 所以再来看看 面试题
面试题图解
面试题一
- 题目
console.log('start')
setTimeout(()=>{
console.log('timeout')
},0)
new Promise((resolve,reject)=>{
resolve()
console.log('resolve')
}).then(()=>{
console.log('then')
})
console.log('end')
- 图解
面试题二
- 题目
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
- 图解
- 值得一提,如果这个题目的两个定时器加了时间,那么,第二第三的宏任务执行顺序会根据时间去更改执行顺序如下图
END
文章编写仓促,有问题欢迎指出,想法是希望以后遇到这类问题,手到擒来。互勉。很多内容,我觉得原作者写的非常好,所以有所借鉴,感谢。
网友评论