前言:本人表述能力不太好,若是有不清晰的地方请必定回复,我会改。
javascript
先肯定几个概念:html
1.单线程:做为浏览器脚本语言,用于解释用户操做,为了不复杂性,js设计之初就是单线程的,这个是毋庸置疑的,也不会改变。
2.[同步,异步,阻塞,非阻塞](https://www.zhihu.com/question/19732473):
同步和异步关注的是消息通讯机制,区别在因而否等待结果返回。
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。
3.执行栈,任务队列:当调用js代码的时候,会生成一个执行上下文。当开始调用一系列的方法,这些方法就存储在执行栈中,等待依次执行。执行栈是执行同步任务。任务队列存放执行当前上下文的异步任务
复制代码
单线程意味着事件是一个一个执行的,前一个执行的时候,后一个须要等待着。但前一个如果网络请求,可能长时间没有回复,就容易致使CPU浪费。执行完同步以后再执行异步,解决了一部分等待的问题。同步的任务在执行栈上执行,遇到异步就放进任务队列里,执行栈中的执行完后执行异步队列。 所谓循环,就是上述事情在重复执行。它常常按照相似以下的方式来被实现:java
while (queue.waitForMessage()) {
queue.processNextMessage();
}
复制代码
事件循环是一种运行机制,js引擎须要执行的时候,将须要执行的消息放进执行栈中,开辟执行上下文。事件循环就是一直重复循环检查执行栈中是否有待执行的消息,当消息完整的执行完后,检查是否有未执行的消息,有就继续执行,没有保持监听。web
如下这种简单代码怎么执行呢?chrome
function test () {
console.log(1);
console.log(2);
}
复制代码
那若是有函数调用呢?执行栈如何处理?api
function foo(b) {
var a = 10;
return a + b + 11;
}
function bar(x) {
var y = 3;
return foo(x * y);
}
console.log(bar(7)); // 返回 42
复制代码
函数调用的时候,执行栈中增长了被调用的函数的上下文,执行完被调用的函数后再继续执行当前函数。 项目中有不少异步代码。好比定时器,这些代码会安排在任务队列里,等待当前主函数执行后依次执行。promise
console.log('这是开始');
setTimeout(function cb() {
console.log('这是来自第一个回调的消息');
});
console.log('这是一条消息');
setTimeout(function cb1() {
console.log('这是来自第二个回调的消息');
});
console.log('这是结束');
复制代码
ECMAScript 2015 引入了 Promises(也在 ES6 / ES2015 中引入) ,使用了做业队列(Job Queue)概念,这是一种尽快执行异步函数的方法。异步队列分为两种,消息队列(也有叫宏任务)和做业队列(也有叫微任务)。执行顺序为: 当前执行上下文 -> 微任务 -> 宏任务
根据事件循环理论分析代码浏览器
var t = new Promise((resolve, reject) => {
console.log('宏事件');
resolve()
}).then(() => {
console.log('微事件');
})
setTimeout(() => {
console.log(t.then(opt => {
console.log('内层微事件')
}));
console.log('内层宏事件')
})
console.log('外层事件');
复制代码
事件循环是js代码执行顺序的解释,可是这里面没有说到何时会对用户界面产生影响。 我在W3C的文章上看到的是这样的:bash
-运行JS代码
-运行微任务队列
-执行布局和IO工做
-运行宏任务队列。
复制代码
有结论,很美好,验证下。网络
<!DOCTYPE html>
<html lang="en">
<body>
<div class="outer" style="width:200px;height:200px;background-color: #ccc"></div>
</body>
<script> var outer = document.querySelector('.outer'); function onClick() { alert('start') outer.innerHTML = 'main func'; alert('main func do') setTimeout(function () { alert('setTimeout start') outer.innerHTML = 'setTimeout'; alert('setTimeout end') }, 10); Promise.resolve().then(function () { alert('Promise start') outer.innerHTML = 'Promise'; alert('Promise end') }); } outer.addEventListener('click', onClick); </script>
</html>
复制代码
咱们在各种任务里增长了DOM渲染,在DOM渲染的先后增长了弹窗(debug模式下不同的机制,不讨论),在Chrome(其余浏览器不同)上执行,发现Promisehtml end
打印出来后,inner
里才有了Promise
字样,任务结束后,字样改为了setTimeout
。上面的结论在chrome是ok的。
参考文章: