JS执行机制
在讲解同步异步之前先来了解一下js的执行机制吧,JavaScript是一门单线程的、非阻塞的脚本语言。单线程意味着,JS 代码在执行的任何时候,都只有一个主线程来处理所有的任务,而js代码一旦报错,后面的代码将不再执行,这也就意味着js无法进行多线程编程,但是js中存在着无处不在的异步概念,我们如何理解呢?理解异步和非阻塞靠的就是 Event Loop(事件循环);
event loop
EventLoop 轮询处理线程:
我们可以把它理解为一个中介,在主线程、异步线程与消息队列三者之间进行交流与沟通。如下图所示:从主线程那里顺时针的看,整个的流程是循环往复的。只有当主线程的同步代码都执行完了,才会去队列里看看还有什么要执行的。
同步与异步:
- 同步任务: 立即执行的任务队列,比如一个简单的函数;
- 异步任务: 请求接口发送 ajax,发送 promise,或时间计时器等等;
异步任务又分为:微任务与宏任务
微任务:promise,async/aswait
宏任务:setTimeout,setInterval,Ajax,Dom事件
在任务队列中微任务比宏任务优先执行;下面的代码中我们来看一下微任务宏任务与dom渲染的执行顺序
const p1 = document.createElement('p');
p1.innerHTML = '一段文字';
// const p2 = `<p>一段文字</p>`;
// const p3 = `<p>一段文字</p>`;
document.querySelector('#container').appendChild(p1);
// 微任务 dom渲染前触发
Promise.resolve().then(() => {
console.log('微任务lenght1', document.querySelector('#container').children.length);
alert('promise then') //Dom渲染了吗 -没有
})
// 宏任务 dom渲染后触发
setTimeout(() => {
console.log('宏任务length2', document.querySelector('#container').children.length);
alert('setTimeout') //Dom渲染了吗 -渲染了
})
/*
顺序:
微任务lenght1 1
alert('promise then')
<p></p>
宏任务length2 1
alert('setTimeout')
*/
代码运行后可以得出以下两点:微任务 dom渲染前触发,宏任务 dom渲染后触发;下面的图带大家看微任务宏任务在event loop中的执行,再执行代码时,微任务会放在 mico task queue中而不是web APIS中
下面是我对于同步异步执行顺序的总结:
- 首先走同步,call stack清空
- call stack清空后执行微任务
- 尝试dom渲染
- 触发event loop执行宏任务