宏任务和微任务

1. 进程、线程和协程

进程进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
线程线程是进程中的一个实体,是被系统独立调度和分派的基本单位 ,分为主线程和子线程(主线程的优先级要绝对大于子线程)
协程协程是一种比线程更加轻量级的一种函数 正如一个进程可以拥有多个线程一样,一个线程可以拥有多个协程。

三者的不同 :

  • 协程既不是进程也不是线程,协程仅是一个特殊的函数。协程、进程和线程不是一个维度的。
  • 一个进程可以包含多个线程,一个线程可以包含多个协程。虽然一个线程内的多个协程可以切换但是这多个协程是串行执行的,某个时刻只能有一个线程在运行,没法利用CPU的多核能力。
  • 协程与进程一样,也存在上下文切换问题。
  • 进程的切换者是操作系统,切换时机是根据操作系统自己的切换策略来决定的,用户是无感的。进程的切换内容包括页全局目录、内核栈和硬件上下文,切换内容被保存在内存中。 进程切换过程采用的是“从用户态到内核态再到用户态”的方式,切换效率低。
  • 线程的切换者是操作系统,切换时机是根据操作系统自己的切换策略来决定的,用户是无感的。线程的切换内容包括内核栈和硬件上下文。线程切换内容被保存在内核栈中。线程切换过程采用的是“从用户态到内核态再到用户态”的方式,切换效率中等。
  • 协程的切换者是用户(编程者或应用程序),切换时机是用户自己的程序来决定的。协程的切换内容是硬件上下文,切换内存被保存在用自己的变量(用户栈或堆)中。协程的切换过程只有用户态(即没有陷入内核态),因此切换效率高。

2. 同步任务和异步任务

js 属于一种单线程语言,但是它可以处理不同的异步请求,原因就是在于

在js执行任务时会产生两种任务,就是 同步任务 和 异步任务

  • 同步任务 : 读取之后,依次从上到下,从左到右进行执行
    • 声明语句
    • for()
    • 赋值
  • 异步任务 : 通过任务队列机制,(先进先出原则),进行协调
    • ajax 网络请求
    • setTimeout定时函数

3. 任务队列

在任务队列中分成两种 : 宏队列微队列

  • 宏队列 : 每次执行栈执行的代码 (包括每次从事件队列中获取一个事件回调并放到执行栈中执行)

  • 微队列 : 在当前 task 执行结束后立即执行的任务

    宏队列和微队列主要包括的内容 :

    宏队列微队列
    script(整体代码)Promise.then
    setTimeoutObject.observe
    setIntervalMutationObserver
    I/Oprocess.nextTick(Node.js 环境)
    UI交互事件
    postMessage
    MessageChannel
    setImmediate(Node.js 环境)

在这里插入图片描述

任务队列的执行过程 :

  1. 先执行一个宏任务
    - 执行过程中如果产出新的宏/微任务,就将他们推入相应的任务队列
  2. 然后执行同一层宏任务里面的微任务,有几个微任务就执行几个 (同层)
  3. 之后再执行宏任务

在这里插入图片描述

代码理解

为了更加方便的理解,直接在代码中注释

Promise 的执行

   //子线程,放到最后输出
       setTimeout(()=>{
           console.log(0);
       })
       //主线程  同步
       new Promise((resolve, reject)=>{
          //第一位的输出,  1
           console.log(1);// 主线程 同步 所以第一个输出
           resolve();
       }).then(()=>{
   				// 第四位输出, 2
           console.log(2);// 主线程 -> 宏队列 -> 微队列 (再按照从上到下的顺序)
           new Promise((resolve, reject)=>{
             // 第五位输出,3
               console.log(3);// 主线程 -> 宏队列 -> 微队列(与 2 同一个层级)
               resolve();//调用
           }).then(()=>{
   						// 第七位的输出,4
               console.log(4);// 主线程 -> 宏队列 -> 微队列 -> 微队列
           }).then(()=>{
   						// 第9位的输出,5
               console.log(5);// 主线程 -> 宏队列 -> 微队列 -> 微队列 -> 微队列 (主线程中层级最深)
           })
       }).then(()=>{
   				// 第八位的输出,6
           console.log(6);// 主线程 -> 宏队列 -> 微队列 -> 微队列  (与 4 层级相同)
       })
   		// 主线程  同步
       new Promise((resolve, reject)=>{
          //第二位的输出  7
           console.log(7);
           resolve();
       }).then(()=>{ 
   				// 第六位输出,8
           console.log(8);//分层级,主线程 -> 宏队列 -> 微队列
       })

   		// 主线程  同步
   		// 第三位输出  9
       console.log(9);
  • 输出结果 : 1 7 9 2 3 8 4 6 5 0

注意点 :

  • 主线程优先级高于子线程,所以先执行主线程的内容,最后执行子线程的内容
  • new Promise(...) 中的代码属于 同步代码,会被立即执行
  • then() 之后的代码是一个异步执行的代码, 属于微任务
  • 一条主线程有多条子线程,并且从上到下运行时,遇到那一条子线程就必须运行结束该子线程后才能运行下一条线程
  • setTimeout() 是一个宏任务,但是在子线程中,该方法的第二个参数为了告诉 JavaScript 再过多长时间把当前任务添加到队列中。

async / await 的执行

   async function async1() {
   	//第一个数字,1 
     console.log("1");//被执行的顺序优先,所以 主线程 -> 宏任务
   	//第五个数字 , 2
     await async2();
     console.log("2");//遇到 async2,输出:async2,并将 then(async1 end)加入微任务
   }
   async function async2() {
   //第二个数字,3
     console.log("3");//主线程 -> 宏任务
   }
   async1();//从上到下依次执行,首先先调用的函数
   
   setTimeout(() => {
     console.log("4");//子线程 -> 宏任务
   }, 0);
   
   new Promise(function (resolve) {
   //第三个数字 , 5
     console.log("5");//主线程 - > 宏任务
     resolve();
   }).then(function () {
     console.log("6");//主线程 -> 微任务
   });
   //第四个数字 , 7
   console.log("7");//主线程 - > 宏任务
  • 输出结果 : 1 3 5 7 2 6 4

注意点:

  • async 函数和普通 函数没有什么不同,他只是表示这个函数里有异步操作的方法,并返回一个 Promise 对象
  • 因为 async 函数总是返回一个 Promise , 所以 await async2()await promise
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值