异步任务执行机制

本文详细介绍了JavaScript的事件循环机制,包括同步任务、异步任务、宏任务和微任务的区别与执行顺序。重点讲解了Promise和await在异步编程中的作用,以及它们如何影响任务队列的执行。通过三个经典异步编程题目,解析了任务执行的顺序和时机,帮助理解JavaScript的异步处理模型。
摘要由CSDN通过智能技术生成

1、任务队列

  • JS分为同步任务和异步任务;
  • 同步任务都在主线程上执行,形成一个执行栈;
  • 主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件;
  • 一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

2、宏任务

macrotask(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行),浏览器为了能够使得JS内部macrotask与DOM任务能够有序的执行,会在一个macrotask执行结束后,在下一个macrotask 执行开始前,对页面进行重新渲染。

macrotask主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。

3、微任务

microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。所以它的响应速度相比setTimeout会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)。

4、运行机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

                                                                      

5、Promise和await

Promise中的代码是被当做同步任务立即执行的,then 则会被分发到 微任务 的 Promise 队列中去

await后面的表达式会先执行一遍,将await后面的代码加入到微任务中,然后就会跳出整个async函数来执行后面的代码

6、异步编程经典题目

(1)变形一:

function test() {
	async function async1() {		//1、创建一个async1函数
		console.log('async1 start');//6、控制台打印async1 start
		await async2();				//7、执行async2,下面的代码需要等待返回正确的Promise后才执行, 添加微任务1
		console.log('async1 end');	//14、执行微任务1, 控制台打印async1 end
	}
	async function async2() {		//2、创建一个async2函数
		console.log('async2');	    //9、控制台打印async2
	}
	console.log('script start');	//3、控制台打印script start
	setTimeout(function() {	 		//4、设置一个定时器, 添加宏任务1
		console.log('setTimeout');	//16、执行宏任务1, 控制台输出 setTimeout
	}, 0)
	async1();						//5、执行async1
	new Promise(function(resolve) { //10、立即执行new Promise
		console.log('promise1');	//11、控制台打印promise1
		resolve();				    //12、添加微任务2
	}).then(function() {
		console.log('promise2');	//15、执行微任务2, 控制台打印promise2
	});
	console.log('script end');		//13、控制台打印script end  
}
test();

// 打印结果:
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

(2)变形二:

function test() {
	async function async1() {
		console.log('async1 start');
		await async2();
		console.log('async1 end');
	}
	async function async2() {
		//async2做出如下更改:
		new Promise(function(resolve) {
			console.log('promise1');
			resolve();
		}).then(function() {
			console.log('promise2');
		});
	}
	console.log('script start');
	setTimeout(function() {
		console.log('setTimeout');
	}, 0)
	async1();
	new Promise(function(resolve) {
		console.log('promise3');
		resolve();
	}).then(function() {
		console.log('promise4');
	});
	console.log('script end');
}
test();

// 打印结果:
// script start
// async1 start
// promise1
// promise3
// script end
// promise2
// async1 end
// promise4
// setTimeout

(3)变形三:

function test() {
	async function async1() {
		console.log('async1 start');
		await async2();
		//更改如下:
		setTimeout(function() {
			console.log('setTimeout1')
		}, 0)
	}
	async function async2() {
		//更改如下:
		setTimeout(function() {
			console.log('setTimeout2')
		}, 0)
	}
	console.log('script start');
	setTimeout(function() {
		console.log('setTimeout3');
	}, 0);
	async1();
	new Promise(function(resolve) {
		console.log('promise1');
		resolve();
	}).then(function() {
		console.log('promise2');
	});
	console.log('script end');
}
test();

// 打印结果:
// script start
// async1 start
// promise1
// script end
// promise2
// setTimeout3
// setTimeout2
// setTimeout1

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值