js中的同步任务,异步任务,宏任务与微任务,事件循环

由于js是一种单线程语言,同一时间,js代码只能在一个主线程上执行,但是,js通过同步任务和异步任务可以模仿多线程
注:js为什么只能是单线程:
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准。

同步任务,异步任务简介

  • 同步任务:同步任务是按顺序执行的任务,每个任务需要等待前一个任务完成后才能开始执行。在执行同步任务期间,程序会阻塞并等待任务完成,然后再继续执行下一个任务。如console.log,
  • 异步任务:异步任务是不按照顺序执行的任务,其执行不会阻塞程序的运行。异步任务会被提交给异步执行的机制(如事件循环、回调函数等),并在后台或其他线程中执行。在任务完成后,会通过回调函数、Promise 或其他机制通知程序任务已完成,然后执行相应的回调函数或继续执行后续的代码。异步任务分为宏任务与微任务

宏任务,微任务分类

宏任务包括:

  1. 定时器任务(setTimeout、setInterval)
  2. I/O 操作任务:包括文件读写、网络请求等需要进行 I/O 操作的任务。
  3. UI 渲染任务:更新页面的渲染任务,例如重绘页面、处理用户交互等。
  4. 消息事件任务:处理消息队列中的事件,例如点击事件、键盘事件、鼠标事件等。
  5. 页面生命周期任务:与页面生命周期相关的任务,例如页面加载、卸载等。
  6. 整体script

微任务包括:

  1. Promise 回调:Promise 对象的 then 、finally和 catch 方法中的回调函数。
  2. MutationObserver:观察 DOM 变化并在变化发生时执行的任务。
  3. process.nextTick(Node.js):在事件循环的当前阶段结束后立即执行的任务。

同步任务,宏任务,微任务执行顺序(事件循环)

事件循环是处理异步任务的一种机制,协调js代码和处理时间的顺序.事件循环的核心思想是将异步任务分为不同的阶段,并按照优先级依次执行。它由以下几个组件组成:
调用栈:用于存储执行上下文的栈结构。同步任务会按照顺序进入调用栈执行,函数调用会形成栈帧,执行完成后出栈。
宏任务队列,微任务队列

  1. 执行同步任务:从上到下按顺序执行代码中的同步任务,直到遇到异步任务。将宏任务依次放入宏任务队列,将微任务依次放入微任务队列
  2. 执行微任务:执行完所有的同步任务后,将微任务从队列中调入主线程执行,开始执行当前的微任务。微任务的执行顺序是先进先出
  3. 执行宏任务:在当前微任务全部执行完毕后,将宏任务从队列中调入主线程执行,开始执行当前的宏任务,每一个宏任务执行完后,都会检查是否存在待执行的微任务(也就是说马上执行该宏任务执行过程中产生的微任务),若有,则执行完所有的微任务后再执行下一个宏任务。宏任务的执行顺序是先进先出
  4. 开始循环直到所有任务执行完毕
console.log('同步任务1')
setTimeout(function (){ 
	console.log('异步宏任务1');
},0);
Promise.resolve().then(()=> {
    console.log('异步微任务1')
});
console.log('同步任务2')
Promise.resolve().then(()=> {
    console.log('异步微任务2')
});
setTimeout(function (){ 
	console.log('异步宏任务2');
    console.log('异步宏任务3');
},0);
new Promise(function(resolve) {
    console.log('同步任务3');
    resolve();
}).then(function() {
    console.log('异步微任务3')
})

// 同步任务1
// 同步任务2
// 同步任务3
// 异步微任务1
// 异步微任务2
// 异步微任务3
// 异步宏任务1
// 异步宏任务2
// 异步宏任务3

async 和await

es7引入了async 和await,可以在不阻塞主线程的情况下用同步代码实现异步访问资源的能力.

  • async
    async 关键字用于定义一个函数,表示该函数具有异步特征,但是总体上其代码仍然是同步求值的。比如
async function foo() {console.log(1);}
foo();
console.log(2);//1 2

异步函数在执行过程中可以包含 await 表达式。
异步函数如果用return返回了值,这个值会被Promise.resolve()包装成一个 Promise 对象,当然也可以直接返回一个promise对象(如果没有return则会返回undefined

async function foo() {
	console.log(1);
	return 3//返回值为 Promise {<resolved>: 3}。
}
foo().then(console.log)
console.log(2);
//1 2 3
  • await
    await 必须用在async函数中,用于暂停异步函数的执行,等待右侧表达式的结果,这个结果是promise对象或者其他值。
    如果它等到的不是一个 promise 对象,那 await 表达式的运算结果就是它等到的东西。
    当遇到 await 表达式时,异步函数会暂停执行,并等待 Promise 对象的状态变为 resolved(解析)或 rejected(拒绝)。
    如果 Promise 对象被解析,await 表达式将返回解析的值;如果 Promise 对象被拒绝,将抛出一个异常。
async 和await执行顺序

async方法内部,当程序执行到await方法时,会阻塞await方法后面的程序,进入await方法内部并执行到return前,然后跳出该async方法,执行与该async方法并列的同步任务。同步代码执行完,再回到async内部,继续执行await后面的代码。

function fn() {
	console.log(3)
	return 5
}
async function foo() {
	console.log(2)
	console.log(await fn());
	console.log(6);
}
console.log(1);
foo();
console.log(4)//1 2 3 4 5 6

注意,若await右侧的值不是一个异步任务,而是立即可用的值的话,async函数的其余部分依然会被异步求值

async function foo() {
	console.log(2)
	await null;//step1.await关键字暂停执行,为立即可用的值null向消息队列里添加一个任务
	//step3.恢复执行,await取得null值
	console.log(4);//step4.打印4
}
console.log(1);
foo();
console.log(3);//step2.同步任务执行完毕后,从消息队列里取出任务,恢复异步函数执行
//1 2 3 4

举例说明

async function async1() {
      console.log(2);
      await async2();
      console.log(6); 
}
async function async2() {
  console.log(3); 
}
console.log(1); 
setTimeout(function () {
  console.log(8);
}, 0);
async1();
new Promise(function (resolve) {
  console.log(4);  
  resolve();
}).then(function () {
  console.log(7);
});
console.log(5); 
  1. 先执行同步任务console.log(1)
  2. 遇到settimeout8,放入宏任务队列
  3. 遇到async1(), 进入async1, 执行同步任务console.log(2), 遇到 await async2(),进入async2(), 执行同步任务console.log(3),没有遇到return,不用管,离开await async2(), async1内所有await之后的语句都被阻塞,放入微任务队列中,离开async1
  4. 离开async1()后,继续执行与async1方法并列的同步任务
  5. 遇到promise,进去console.log(4); 遇到then放进微任务,离开promise
  6. 同步任务console.log(5);
  7. 同步任务全都执行完,执行微任务,执行async1剩余部分console.log(6), 执行thenconsole.log(7);
  8. 微任务执行完毕,执行宏任务settimeout, console.log(8);
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值