console.log('script start');
setTimeout(async function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
这个是查考JavaScript事件循环机制,你的答案是什么?
正确答案是:script start, script end, promise1, promise2, setTimeout
你答对了吗?
我们来看看为什么
- 整体 script 作为第一个宏任务进入主线程,遇到 console.log,输出 script start
- 遇到 setTimeout,其回调函数被分发到宏任务的任务队列(Event Queue)中
- 遇到 Promise,其 then函数被分到到微任务 Event Queue 中,记为 then1,之后又遇到了 then 函数,将其分到微任务 Event Queue 中,记为 then2
- 遇到 console.log,输出 script end
- 至此,任务队列(Event Queue)中存在三个任务,如下表:
宏任务 | 微任务 | setTimeout | then1 | then2 |
---|
执行微任务,首先执行then1,输出 promise1, 然后执行 then2,输出 promise2,这样就清空了所有微任务 执行 setTimeout 任务,输出 setTimeout 至此,输出的顺序是:script start, script end, promise1, promise2, setTimeout
看了答案之后,默默去复习了下,然后总结如下,小笔记。。。。
想好好了解的话,去看看文末的连接就好了,下面就可以不看了。。。我是给自己记得小笔记,哈哈哈哈哈!
“进程” 和 “线程”
什么是进程?
对操作系统来说执行一个任务就是一个进程。
什么是线程?
在一个进程上同时需要执行多个“子任务”。例:在使用word时,同时可以写字,拼写检查,打印等事情,在一个进程内部同时要干多件事,每件事都是一个线程。
JS语言的特性:一门单线程非阻塞的语言
单线程:是由于js最初的用途来决定的,与浏览器交互单线程意味着JS代码在执行的任何时候都是由主线程来处理所有任务
非阻塞:JS在执行异步任务的时候无法立刻返回结果,需要花时间等待,主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定的规则去执行回调函数。
浏览器下JS引擎的事件循环机制
JS在初次执行代码时:会将不同的变量存于内存中的不同位置。
JS调用一个方法的过程:
当调用一个方法时,js会生成与这个方法对应的执行环境(context),又叫做上下文,在执行环境中存在这个方法的私有作用域,上层作用域的指向(this对象),方法的参数。
JS中“同步代码”是如何执行的?
(1)、什么是“执行栈”?——用于方法排队等候的“暂存地”
由于JS是单线程,同一时间只能执行一个方法,其余方法需要排队等候依次调用,所以这个排队等候的地方就是“执行栈”
(2)、关于执行栈中的排队顺序
当JS脚本第一次执行的时候,JS引擎会解析代码并将其中的“同步代码”顺序加入到执行栈,然后从头开始执行,如果当前执行的是一个方法,就会在执行栈中添加这个方法的执行环境,当方法执行完毕会退出执行环境并销毁,回到上一个方法的执行环境,这个过程反复执行,直到执行栈中的代码完全执行完毕。
在一个方法的执行环境中,还可以调用别的方法,甚至可调用自己本身,其结果就是在执行环境中再添加一个执行环境,这个过程是可以无限循环下去的,除非发生“栈溢出”(即超过了使用内存的最大值,造成内存泄露)
js中“异步代码”是如何执行的?
(1)、事件队列(task queue)—— 存放异步事件的地方
JS引擎遇到一个异步事件的时候,并不会一直等待结果,而会将这个事件挂起,继续执行“执行栈”中的其他任务,当这个异步事件返回结果后,js会将这个事件加入到另外一个队列中(即事件队列)
异步事件放入到事件队列中不会立即执行,而是等待执行栈中所有的任务都执行完成,主线程处于闲置状态的时候,主线程会去查找事件队列中是否有任务,如果有,按照顺序依次调用
主线程取出第一位事件,并把事件对应的回调函数放到执行栈中,然后执行同步代码,依次反复,这个过程就叫做“事件循环”。
(2)、异步任务的类别:宏任务和微任务
宏任务和微任务的执行顺序: 主线程会先查看微任务队列是否有事件存在,如果有,先逐一执行,直到微任务全部执行完毕然后再去执行宏任务,如果没有,再去宏任务中取出事件放入到执行栈中执行。
任务队列
所有的任务可以分为同步任务和异步任务,同步任务,顾名思义,就是立即执行的任务,同步任务一般会直接进入到主线程中执行;而异步任务,就是异步执行的任务,比如ajax网络请求,setTimeout 定时函数等都属于异步任务,异步任务会通过任务队列( Event Queue )的机制来进行协调。具体的可以用下面的图来大致说明一下:
Event Loop (事件循环机制)
同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 Event Queue 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。这个概念一定要背下来
在事件循环中,每进行一次循环操作称为tick,通过阅读规范可知,每一次 tick 的任务处理模型是比较复杂的,其关键的步骤可以总结如下:
1.在此次 tick 中选择最先进入队列的任务( oldest task ),如果有则执行(一次)
2.检查是否存在 Microtasks ,如果存在则不停地执行,直至清空Microtask Queue
3.更新 render
4.主线程重复执行上述步骤
可以用一张图来说明下流程:
然后,再看那个题,就理解啦啦啦啦啦啦
引用
深入浅出理解JS事件循环机制
深入理解JavaScript事件循环机制
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!