js 事件循环 【eventloop】-同步异步执行顺序

浏览器是多线程的

浏览器常用的线程

  • GUI渲染线程:渲染和解析界面
  • JS 引擎线程: 渲染和解析JS [浏览器分配一个线程去解析js, 所以js是单线程]
  • 定时器监听线程
  • 事件监听线程
  • http网络请求线程 【同源下,浏览器最多同时分配5~7个http线程】

JS 是单线程运行的,但是异步是如何实现的呢?

js 中的异步操作是借用浏览器的多线程机制, 在基于eventloop 事件循环机制 实现了单线程异步操作。

浏览器加载页面除了开辟堆、栈内存外,还创建了两个队列:

  • webapi(任务监听队列-使用了浏览器的多线程去监听的)
  • eventQueue(事件/任务队列)

首先:当主线程自上而下执行代码中, 如果遇到异步代码 会把异步任务放到webapi中去监听
(浏览器开启新的线程去监听是否可以执行,不会阻碍主线程的渲染,主线程继续往下执行代码)

其次:当异步任务被检测为可以执行了,也不会立即执行,会压入eventQueue排队等待主线程执行

  • 根据微任务还是宏任务放在不同的队列中
  • 谁先进来 谁排在各自队伍的最前边
    PS. 对于定时器来讲 设定一个等待时间 到时间后并不一定立即执行。

最后:当同步代码执行完毕,主线程空闲下来,回去eventQueue中把正在排队的异步任务 按照顺序取出来执行

  • 异步的微任务优先级比较高,无论其中的任务是先放入的还是后放入的 只要有可执行的异步微任务永远先执行他。
  • 同样级别的任务 谁先放入的 先执行谁
  • 是要把任务拿到栈中执行,而且交给主线程执行,所以只要这个拿出来的任务没有执行完,也不会去拿其他的任务。

异步宏任务有哪些,异步微任务有哪些?

  • [异步微任务]
    + requestAnimationDrame
    + Promise.then/catch/finally
    + async/await
    + queueMicrotask 手动创建一个异步的微任务
    + MutationObserer
    + IntersectionObserver
    + …
  • [异步宏任务]
    + settimeout/setinterval
    + 事件绑定/队列
    + xmlhttpRequest/fetch
    + messageChannel

Promise和await运行过程的理解

1、Promise
  • 情况1 p.then(onfulfilled, onreject) 已知实例p的状态和值, 也不会立即执行onfulfilled/onrejected。而是创建异步微任务【先进入webapi中发现状态是可以执行,再挪入eventqueue中等待执行】
  • 情况2 如果不知道实例p的状态,则先把onfulfilled/onrejected储存起来【理解为放入webapi中去监听,只有知道其状态的时候才去执行。】resolve和reject执行之后 立即修改了实例的状态和值,也决定了webapi中监听的方法要执行哪一个,然后挪至eventqueue中,等待主线程中任务执行完毕,再将其拿出来执行。
2、await
  • 立即执行await右边的方法,看其返回的promise实例
  • 会把当前上下文中 await后边的代码当做异步的微任务
    • 加入到webapi中进行监听要不要被执行
    • 如果可以执行 进入eventQueue中等待被执行

举个例子

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' );

在这里插入图片描述

let body = document.body;
body.addEventListener('click', function() {
    Promise.resolve().then(() => {
        console.log(1)
    })
    console.log(2)
})
body.addEventListener('click', function() {
    Promise.resolve().then(() => {
        console.log(3)
    })
    console.log(4)
})

解释:
1、首先将click的handler函数依次加入webapi队列等待被触发
2、点击body后 依次触发两个handler,这时将两个函数放到了异步宏任务队列等待执行
3、js主线程空闲后,从异步宏任务队列中取出第一个handler进行执行
4、发现第一个handler中含有一个Promise.then(),此时会将.then()中的执行方法放入webapi队列,因为立马执行了resolve,所以console.log(1)会进入异步微任务队列,等待被执行
5、按顺序执行console.log(2),此时js主线程又进入空闲。
6、这时候异步微任务队列中有待执行的任务,会优先被执行。所以打印出1。此时js主线程空闲
7、微任务列表中没有任务才回去宏任务列表查看。发现第二个handler。开始执行。
8、重复4、5、6至此结束

所以经过应该是 2 1 4 3

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值