JavaScript 的异步新道路 ES11 宣布!!
ES11 是 JavaScript 的新版本,其中最重要的变化是异步编程方面的新特性。在这个版本中,出现了微任务和宏任务这两个概念。在底层处理异步任务之前,先来了解一下它们的含义和作用,以及如何在实际编程中应用它们。
什么是微任务和宏任务?
在 JavaScript 中,异步任务可以分为两类:宏任务和微任务。简单来说,宏任务就是浏览器自身的任务,通过 setTimeout
、setInterval
等方法添加到任务队列中的任务就称为宏任务。而微任务是在宏任务执行完成后,在当前任务执行结束前需要完成的任务,主要有 Promise.then
、Object.observe
、MutationObserver
等方法。
我们可以将宏任务理解为主线程中的任务,而微任务是主线程内部的任务。微任务的执行顺序优先于宏任务,也就是说,在一个宏任务执行的期间,如果有微任务需要执行,那么这些微任务会优先被执行。
微任务和宏任务的执行顺序
在 JavaScript 中,任务的执行顺序遵循一个简单的规则:同等级的任务,按照它们被添加到任务队列中的顺序被执行,而不是由它们的类型(微任务或宏任务)来判断。
假设当前主线程执行的是一个宏任务,这个宏任务中又包含了若干微任务。这时候,程序会先执行这些微任务,然后再去执行下一个宏任务。
例如,下面的代码中,我们会发现先执行了 Promise
中的两个微任务,再执行 setTimeout
中的宏任务:
console.log('start') Promise.resolve().then(() => console.log('promise')) setTimeout(() => console.log('timeout'), 0) console.log('end')
输出结果:
start end promise timeout
微任务和宏任务的使用场景和指导意义
- 微任务使用场景
微任务通常用于需要立即执行的任务,比如显示加载动画、异步状态的更新等等。
使用微任务的好处是,因为它们的执行顺序不受宏任务的影响,所以可以确保它们及时地被执行。
- 宏任务使用场景
宏任务通常用于需要等待一段时间后才能执行的任务,比如定时器、I/O 操作、事件监听等等。
使用宏任务的主要好处是,它们可以确保当前任务的执行不会超时,从而使得浏览器能够在循环调用中合理分配 CPU 资源,保证不阻塞页面渲染。
示例代码
在下面的例子中,我们使用 Promise
作为微任务,根据需要来决定使用 setTimeout
还是 setInterval
来创建宏任务。在定时器到达之前,我们可以将某些 UI 组件设置为不可用状态,从而避免用户重复点击:
-- -------------------- ---- ------- -------- ------------- - ----- ------ - --------------------------------- -------------------- - ------- - -------- ------------- - ----- ------ - --------------------------------- -------------------- - ------ - -------- ------------------- - ------------- --------------- -------------- -- ---------------- ---------- -- - -------------- ------------- -- ------------ -- - -------------- ------------- -- - -------- -------------- - ----- --------- - ------------------------------------ ------------------- - ---- - -------- -------------- - ----- ----- - -------------------------------- ------------------- - ------- - -------- ---------------- - ----- ------- - --------------------------------------- --- ---- - - -- - - --------------- ---- - ------------------- - ---- - - -------- --------------- - ----- ------- - --------------------------------------- --- ---- - - -- - - --------------- ---- - ------------------- - ----- - - -------------------------------------------------------------- -- -- - ----- -------- - ---------------------------------------------- ---------------- ------------- -- - ------------------- --------------- -- ----- --展开代码
在上面的代码片段中,我们使用 showLoading
和 hideLoading
函数控制显示和隐藏加载动画。在 fetchData
函数中,我们使用 Promise
来将更新 UI 和隐藏加载动画的操作添加为微任务。
在 disableButtons
和 enableButtons
函数中,我们使用 for
循环将按钮元素的 disabled
属性设置为 true
和 false
,以确保在数据加载期间不会发生用户的重复点击。
在事件监听器中,我们调用 disableButtons
函数,将所有按钮设置为不可用,然后使用 setTimeout
创建一个 2 秒后触发的宏任务,在宏任务执行之前,用户不能再次使用按钮进行数据加载。
在宏任务触发的回调函数中,我们调用 fetchData
函数进行数据加载,然后使用 enableButtons
函数使得按钮重新可用。
总之,微任务和宏任务的使用场景不同,但都可以帮助我们更好地实现异步编程。熟练掌握它们的概念和使用方法,有助于我们更加高效地编写复杂的 JavaScript 代码。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67b96e04306f20b3a67cbc21