2021-03-05

javascript中的事件循环(Event Loop)

 

什么是事件循环(Event Loop)?


首先我们要知道javascript是单线程运行的,遇到大的外部文件时,会阻塞下面程序的运行,造成用户体验不好,为了解决这一问题,则用到了计算机系统的一种运行机制,即事件循环(Event Loop)。

同步任务和异步任务。


在javascript中,所有的任务都能分为同步任务和异步任务。

  • 同步任务:立即执行的任务,直接进入主线程执行。
  • 异步任务:异步执行的任务,比如ajax请求,setTimeout定时函数等。

异步任务有分为宏观任务和微观任务

  • 宏观任务常见的为:setTimeout、setInterval
  • 微观任务常见的有:promise.then()、MutaionObserver、process.nextTick(Node.js)

在一个事件循环中,异步事件返回的结果会被放到一个任务队列中,根据这个异步事件的类型会被对应的宏任务队列或者微任务队列。当执行栈为空的时候,主线程会查看微任务队列是否有事件存在,如果不存在,则去宏任务队列中的事件并把对应的回调加入到当前的执行栈。如果存在一次执行队列事件对应的回调,直到微任务队列为空,然后执行宏任务队列中的时间,把对应的回调加入执行栈。如此反复执行则为事件循环。

接下来我们来看个例子:

console.log('1');

setTimeout(() => {		
    console.log('2');
},0);

let p = new Promise((resolve, reject) => {
	console.log('3');
	resolve();
});

p.then(() => {
	console.log('4');
})

console.log('5');



//1 3 5 4 2

我们来分析一下上面代码的执行:

1.首先打印 1

2.执行到settimeout时,此为宏任务,放入宏任务队列。

3.执行promis打印3,resolve()为微任务,放入微任务队列

4.最后打印5,到此为止这条宏任务执行完毕,接着看看是否有微任务,则promis中有一个微任务及p.then()打印4,微任务队列执行完毕。

5.查看是否有宏任务,即setTimeout,执行打印2,则结果为“1 3 5 4 2”

async await


async为异步的意思,await为等待,及await下面的代码要等待await执行完毕在执行。

async function fun() {
	console.log('1');
	await fun1();
	console.log('2'); //阻塞
}

function fun1() {
	console.log('3');
}

fun()
console.log('4');


//1 3 4 2

上面的例子中,await会阻塞下面的代码(即加入微任务队列),先执行async外面的同步代码,执行完后在回到async函数中,在执行阻塞代码,其结果为1 3 4 2。

 

通过对上面的了解,我们大致的了解了事件循环的执行顺序,下面我们来看一个综合的例子

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2() {
    console.log('async2')
}

console.log('script start')

setTimeout(function () {
    console.log('settimeout')
})

async1()

new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})

console.log('script end')

 

分析执行过程

1.执行上面的代码首先执行console.log('script start'),打印‘script start’。

2.接着执行settimeout,其为宏任务,放入宏任务队列。

3.执行async1(),首先打印‘async1 start’,接着执行await async2(),则打印‘ async2 ’,阻塞下面的代码,放入微任务队列,跳出async1()函数,接着执行。

4.执行new Promise,打印‘promise1’,then为微任务,放进微任务队列。

5.最后执行console.log('script end');打印‘script start’。此时的同步任务执行完,接着执行微任务,及async,打印‘async1 end’

6.接着继续执行微任务,即promise.then,打印‘promise2’。

7.上一个宏任务执行完,开始下一个宏任务,即settimeout,打印‘settimeout’

上面例子的打印结果为:script start、async1 start、async2、promise1、script end、async1 end、promise2、settimeout。

 

事件循环图

参考:https://mp.weixin.qq.com/s/9iN7XR1PwXfua8SrabOi5w

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值