有免费制作单页的网站吗,做早餐煲汤网站,qq群推广平台,品牌网站建设价格天天快递浏览器事件循环(事件轮询) 文章目录 浏览器事件循环(事件轮询)1.浏览器事件循环流程2.同步任务、异步任务、宏任务和微任务概念同步任务#xff1a;异步任务#xff1a;宏任务#xff1a;微任务#xff1a; 3.宏任务和微任务区别异步任务的分类#xff1a;异步任务执行顺序…浏览器事件循环(事件轮询) 文章目录 浏览器事件循环(事件轮询)1.浏览器事件循环流程2.同步任务、异步任务、宏任务和微任务概念同步任务异步任务宏任务微任务 3.宏任务和微任务区别异步任务的分类异步任务执行顺序 4.Vue中涉及事件循环5.$nextTick 1.浏览器事件循环流程
浏览器事件循环Browser Event Loop是浏览器用于处理用户输入、网络请求、渲染和其他异步事件的机制。这个循环确保了 JavaScript 代码的执行是非阻塞的允许浏览器同时处理多个任务从而提高用户体验。以下是浏览器事件循环的详细说明 调用栈 当一个 JavaScript 脚本开始执行时它会被放入调用栈。调用栈是一个数据结构用于跟踪执行上下文函数调用的堆栈。 同步任务 在调用栈中的代码是同步任务它们会按照执行的顺序逐一执行。如果有函数调用它们会被压入调用栈直到执行完成。 异步任务触发 当浏览器遇到异步任务例如定时器、事件监听器、网络请求等它会将这些任务放入任务队列中。 任务队列 任务队列是一个先进先出FIFO的数据结构用于存储异步任务。有多个任务队列其中包括宏任务队列和微任务队列。 宏任务队列 包括 DOM 操作、用户交互事件、定时器等。宏任务完成后会将一个新的同步任务放入调用栈。 微任务队列 包括 Promise 回调、MutationObserver 回调等。微任务会在当前宏任务执行完成后、下一个宏任务执行前执行。 事件循环Event Loop 当调用栈为空时事件循环开始工作。它会检查宏任务队列如果有任务将任务推入调用栈执行。执行完毕后再检查微任务队列如果有微任务将其依次推入调用栈执行。这个过程会一直重复形成一个循环。 宏任务执行 从宏任务队列中选择一个任务执行完毕后再选择下一个宏任务。 微任务执行 在宏任务执行完毕后依次执行微任务队列中的所有任务。
这个事件循环的机制确保了 JavaScript 的异步执行同时避免了阻塞主线程。这对于处理用户交互、网络请求等异步任务是非常重要的以确保应用程序的响应性和性能。
2.同步任务、异步任务、宏任务和微任务概念
同步任务
同步任务是按照它们被调用的顺序依次执行的任务一个接一个地在调用栈中运行。在执行同步任务时JavaScript 引擎会一直等待任务执行完毕然后才继续执行下一个任务。
console.log(Task 1);
console.log(Task 2);
console.log(Task 3);
// ...异步任务
异步任务是不会阻塞后续代码执行的任务。它们将在将来的某个时间点执行可以是由浏览器环境触发的事件也可以是由开发者手动触发的异步操作。
// 异步任务示例定时器
setTimeout(function() {console.log(1000ms);
}, 1000);// 异步任务示例事件监听器
document.addEventListener(click, function() {console.log(点击);
});宏任务
宏任务是由浏览器环境提供的任务包括 I/O 操作、渲染、事件处理等。在事件循环的每一轮中只会执行一个宏任务。常见的宏任务包括 setTimeout、setInterval、DOM 操作、AJAX 请求等。
// 宏任务示例setTimeout
setTimeout(function() {console.log(2000ms);
}, 2000);// 宏任务示例AJAX 请求
fetch(https://api.abc.com/data).then(response response.json()).then(data console.log(AJAX));微任务
微任务是在当前宏任务执行完毕后、下一个宏任务执行前触发的任务。它们有着更高的优先级会在宏任务中的异步操作之前执行。常见的微任务包括 Promise 的回调、MutationObserver 等。
// 微任务示例Promise
Promise.resolve().then(function() {console.log(微任务1);
});// 微任务示例MutationObserver
const observer new MutationObserver(function() {console.log(微任务2);
});observer.observe(document.body, { attributes: true });document.body.setAttribute(class, some-class);在事件循环中首先执行当前调用栈中的同步任务然后检查并执行宏任务队列中的一个宏任务接着执行微任务队列中的所有微任务。这个过程会一直重复确保了 JavaScript 引擎的异步执行和非阻塞特性。
3.宏任务和微任务区别
宏任务和微任务都是异步任务的一种但它们之间存在一些区别。
异步任务的分类 宏任务 包括整体的代码、setTimeout、setInterval、AJAX 请求、DOM 操作等。宏任务会在当前调用栈执行完毕后从宏任务队列中取出一个任务执行。 微任务 包括 Promise 的回调、MutationObserver、process.nextTick 等。微任务会在当前宏任务执行完毕后、下一个宏任务执行前触发且微任务会在宏任务中的异步操作之前执行。
异步任务执行顺序
执行同步任务按照代码顺序逐一执行。执行当前宏任务从宏任务队列中取出一个任务执行。执行微任务队列中的所有微任务。重复步骤 2 和 3直到宏任务队列为空。
console.log(同步 1);// 宏任务
setTimeout(function() {console.log(宏任务 1);// 微任务Promise.resolve().then(function() {console.log(微任务 1);});
}, 0);// 宏任务
setTimeout(function() {console.log(宏任务 2);// 微任务Promise.resolve().then(function() {console.log(微任务 2);});
}, 0);console.log(同步 2);
//同步 1
//同步 2
//宏任务 1
//微任务 1
//宏任务 2
//微任务 2在上面的示例中同步任务同步1、同步2首先执行然后是两个宏任务宏任务1、宏任务2。在每个宏任务执行后会依次执行微任务微任务1、微任务2。这种执行顺序确保了微任务比宏任务更具优先级微任务会在下一个宏任务之前执行。
首先执行同步代码输出 ‘同步 1’ 和 ‘同步 2’。然后两个 setTimeout 中的回调函数被分别添加到宏任务队列。接着执行微任务队列中的任务即两个 Promise 的回调函数。输出 ‘微任务 1’ 和 ‘微任务 2’。再次回到宏任务队列执行第一个 setTimeout 的回调函数输出 ‘宏任务 1’。在这个宏任务中又产生了一个微任务即 Promise 的回调函数输出 ‘微任务 1’。继续执行宏任务队列执行第二个 setTimeout 的回调函数输出 ‘宏任务 2’。同样在这个宏任务中产生了一个微任务即 Promise 的回调函数输出 ‘微任务 2’。
微任务总是在当前宏任务执行完毕后、下一个宏任务执行前执行。微任务 1 和 微任务 2 在它们所属的宏任务setTimeout 的回调函数执行完毕后才得以执行。
4.Vue中涉及事件循环
在Vue.js中事件循环主要涉及到Vue实例的生命周期、响应式数据的更新、以及Vue异步操作的处理。 Vue生命周期钩子 Vue实例在创建、挂载、更新、销毁等阶段都有对应的生命周期钩子函数。这些生命周期钩子函数在特定的时机被触发它们在事件循环中的执行顺序受到影响从而影响Vue实例的行为。例如在created生命周期钩子中Vue实例已经创建但尚未挂载到DOM中。在这个阶段可以进行一些异步操作这些异步操作会在事件循环的下一个周期中执行。 数据更新响应 Vue的响应式系统通过数据的变化来触发视图的更新。当数据发生变化时Vue会通过事件循环的微任务队列将更新操作推送到队列中然后在当前任务执行完成后立即执行微任务队列中的更新操作。这保证了数据更新的响应性同时避免了在同一个任务中频繁地进行DOM更新提高了性能。 Vue.nextTick方法 Vue.nextTick是Vue提供的一个工具方法用于在DOM更新后执行回调函数。在某些场景下比如修改了数据但想要立即获取更新后的DOM状态可以使用Vue.nextTick来确保在下一次事件循环中执行回调。这是因为DOM更新是异步的Vue.nextTick会将回调函数推送到微任务队列中确保在DOM更新后执行。 异步组件加载 Vue支持异步组件加载通过import语法实现。当使用异步组件时组件的加载是异步的。异步组件的加载过程涉及到事件循环确保在组件加载完成后才会进行渲染。这有助于提高应用的性能避免一开始就加载所有组件而是按需加载。 Vue异步操作 在Vue中一些异步操作比如$nextTick、$set等都涉及到事件循环的概念。通过这些异步操作Vue能够在下一个事件循环周期中执行一些需要等待的任务以确保在适当的时机进行DOM更新或其他操作。
5.$nextTick
在Vue中一个经典的例子是使用this.$nextTick来确保在DOM更新完成后执行一些操作。这在处理DOM更新的时候非常有用特别是当需要获取更新后的DOM状态时。
假设有一个按钮点击按钮后触发显示一个Element UI的Modal对话框并且想在Modal对话框显示后获取它的某些属性例如宽度。
templatedivel-button clickshowModal显示Modal/el-buttonel-dialog :visible.syncdialogVisible title我是一个Dialog!-- Modal 内容 --!-- ... --/el-dialog/div
/templatescript
export default {data() {return {dialogVisible: false,modalWidth: null};},methods: {showModal() {this.dialogVisible true;// 此时 Modal 还未渲染到 DOM 上console.log(Modal 尚未渲染到 DOM 上此时宽度为, this.modalWidth);// 使用 $nextTick 来确保在下一次事件循环中执行回调this.$nextTick(() {// 此时 Modal 已经渲染到 DOM 上this.modalWidth this.$refs.dialog.$el.clientWidth;console.log(Modal 已渲染到 DOM 上宽度为, this.modalWidth);});}}
};
/script当按钮被点击时showModal方法会设置dialogVisible为true显示Modal。然后使用this.$nextTick来确保在下一次事件循环中执行回调函数这个回调函数用于获取Modal对话框的宽度。通过这种方式能够确保在Modal渲染到DOM上后再去获取其属性避免了在Modal还未渲染完成时就尝试获取其属性的问题。