JavaScript执行机制 — 事件循环
【摘要】 事件循环简单介绍及示例
单线程
总所周知,JavaScript是一门单线程语言!
JS作为一种脚本语言,多被用于浏览器中进行Web开发,它的主要用途是通过操作DOM,BOM等达到与用户进行交互的目的。这也就意味着它只能是单线程的,以此来避免多个线程对同一DOM元素进行冲突的操作。
虽然H5出了一个新特性WebWorker为JS创造多线程环境,但多用来计算密集型或高延迟的任务,让主线程流程不被阻塞。但WebWorker也有诸多限制,同源限制,DOM限制,通信限制,脚本限制及文件限制等,这里不多做叙述。
异步
如果JS在执行一行代码时,解析时间过长,例如:大量数据的循环遍历等,那么后面的代码将会被阻塞,暂时无法执行,对用户而言,页面就卡住了,没办法进行迅速有效的交互,此时就需要JS进行异步操作!
异步的实现,也就是JS的执行机制 — 事件循环(event loop)
事件循环
因为JS是单线程的,所以所有的任务都是需要排队的,这里将JS的任务分为两种:
- 同步任务(synchronous):在主线程上排队执行的任务
- 异步任务(asynchronous):不进入主线程,而是进入“任务队列”(task queue)的任务
任务队列也是事件队形,运行机制大致如下:
- 同步任务在主线程上执行,形成一个执行栈(先进先出)
- 当执行栈执行完所有同步任务后,主线程将从“任务队列”中读取事件,执行异步任务
异步任务又细分为:
- 宏观任务:宏观即指宿主,也是就是写代码的人发起的任务(整体代码script,setTimeout,setInterval)
- 微观任务:微观即指JS,由JS引擎发起的任务(Promise.then是Promise的回调函数,process.nextTick)
完整的事件循环:
- 第一轮循环将整体JS当作一个宏任务来运行,主线程判断任务类型,同步任务逐步执行,当遇到异步任务将其推入事件队列(宏任务推入宏任务队列,微任务推入当前宏任务的微任务队列)
- 主线程执行完一轮轮同步(宏)任务后,依次执行当前的所有微任务
- 执行完当前所有任务,结束第一轮循环,开始第二轮循环
- 执行同步(宏)任务,将微任务推入当前的宏任务的微任务队列
- 开始循环往复
示例1:
console.log('1')
setTimeout(function() {
console.log('2')
process.nextTick(function() {
console.log('3')
})
new Promise(function(resolve) {
console.log('4')
resolve()
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6')
})
new Promise(function(resolve) {
console.log('7')
resolve()
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9')
process.nextTick(function() {
console.log('10')
})
new Promise(function(resolve) {
console.log('11')
resolve()
}).then(function() {
console.log('12')
})
})
示例2:
async function testSometing() {
console.log("执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const v1 = await testSometing();
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, v2);
}
test();
var promise = new Promise((resolve) => {
console.log("promise start..");
resolve("promise");
});
promise.then((val) => console.log(val));
setTimeout(()=>{console.log("setTime1")},3000);
console.log("test end...")
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)