同步异步任务的执行过程 | 青训营笔记

112 阅读4分钟

这是我参与【第四届青训营】笔记创作活动的第4天

1.什么是同步任务与异步任务

同步任务

  • 同步任务又叫做非耗时任务,指的是在主线程上排队执行的那些任务
  • 只有前一个任务执行完毕,才能执行后一个任务

异步任务

  • 异步任务又叫做耗时任务,异步任务由js委托给宿主环境进行执行
  • 宿主环境:即js的执行环境,js在浏览器里执行的,宿主环境就是浏览器,在nodejs里执行的,宿主环境就是node
  • 当异步任务执行完成后,会通知js主线程执行异步任务的回调函数

2.同步任务和异步任务的执行过程

  1. 同步任务有js主线程次序执行
  2. 异步任务委托给宿主环境执行
  3. 已完成的异步任务对应的回调函数,会被加入到任务队列中的回调函数,次序执行
  4. js主线程的执行栈被清空后,会读取任务队列中的回调函数,次序执行
  5. js主线程不断重复第(4)步 即EventLoop的工作

代码案例

// 同步任务
console.log('A');

// 异步任务
setTimeout(() => {
	console.log('B');
}, 10);

// 异步任务
setTimeout(() => {
	console.log('C');
}, 0);

// 同步任务
console.log('D');
// 结果:A D C B

在上面的代码中,js主线程遇到同步任务A则立即打印;遇到异步任务B,则交由宿主环境开始计时;与此同时,主线程也执行到异步任务C,则继续交由宿主环境开始计时,计时0ms计时完毕,则把回调函数() => {console.log('C');}放入任务队列中;再接着js主线程执行同步任务D;紧接着异步任务B计时结束后,回调函数也进入任务队列。然后因为主线程执行栈已经清空了,接下来从任务队列里取出任务并且执行。因此最终结果是ADCB

宏任务与微任务

什么是宏任务与微任务

异步任务又分为宏任务和微任务,任务执行的先后次序与这个任务是宏任务还是微任务有关

常见的宏任务与微任务

宏任务

  • 异步ajax请求
  • setTimeout setInterval
  • 文件操作

微任务

  • Promise.then .catch .finally
  • process.nextTick

执行机制

  1. 按序完成同步任务,分好微任务队列,宏任务队列
  2. 同步任务完成后,再查看微任务队列,清空微任务队列后,执行第一个宏任务
  3. 第一个宏任务开始执行 重复(1)
  4. 第一个宏任务里的同步任务清空后,再清空微任务,继续执行第二个任务
  5. 重复(3)(4)

代码案例

// 同步任务1
console.log(1);

// 异步任务2
setTimeout(() => {
	console.log(2);
	new Promise(function (res) {
		console.log(3);
		res();
	}).then(function () {
		console.log(4);
	})

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

// 同步任务3,异步任务4
new Promise(function (res) {
	console.log(6);
	res();
}).then(function () {
	console.log(7);
})


// 同步任务5
console.log(8);

// 结果: 1 6 8 7 2 3 4 5

在上面的代码中,js主线程遇到同步任务1则立即打印1;遇到异步任务2,则交由宿主环境开始计时,计时完交由宏任务队列;主线程继续遇到同步任务3(注意:Promise接收的函数为当前执行栈的,即为同步任务),打印6;然后异步任务4计时完后又交由微任务队列;遇到同步任务5,打印8;此时,宏任务队列有异步任务2,微任务队列有异步任务4,微任务队列未清空,需先执行微任务队列里的回调函数,即打印7;打印7完,微任务队列已清空,开始执行第一个宏任务;打印完2和3后,微任务队列和宏任务队列有新增了两个回调函数;此时微任务队列又未被清空,则先执行微任务队列,即打印4;微任务队列为空,执行第二个宏任务。即打印5;

因此最终结果为1 6 8 7 2 3 4 5