宏任务与微任务执行顺序及对比记录

目录

前言

一、 宏任务、微任务的基本概念

1.宏任务介绍

2.微任务介绍

3.宏任务、微任务发展及出现的原因:

 4.宏任务、微任务的基本类型

二、 事件循环模型(Event Loop)

三、 Promise、async和await 在事件循环中的处理

1.Promise:

        2. async/await :

这个知识点比较容易忽略,以为 await 回来后,直接继续执行后面的代码,这是不对的!

四、 process.nextTick在事件循环中的处理

五、 典型案例

5.1 典型的宏任务、微任务

5.2 宏任务中包含微任务

5.3 微任务中包含宏任务

5.4 async 宏任务

5.5 node 事件执行分析

5.6 综合案例

六、案例分析

6.1 典型的宏任务、微任务

6.2 宏任务中包含微任务

6.3 微任务中包含宏任务

6.4 async 宏任务

6.5 node 事件执行分析

6.6 综合案例

总结起来,宏任务与微任务的执行顺序可以归纳为以下几点:

综上所述,宏任务与微任务的执行顺序是宏任务队列执行完毕之后依次执行微任务队列,然后再从宏任务队列中取出下一个宏任务进行执行。在实际开发中,我们可以根据这个执行顺序来合理地安排任务的执行,以达到更好的效果。


前言

写此之前,也查阅了很多文章,并结合自己的理解,说说对Event Loop模型的理解、以及对Promiseasync/await在任务队列中的影响进行了分析,也给出了多种情形的任务案例以及分析解释,相信大家看完会有所收获;当然,也是自己的理解,难免有所偏差,欢迎大家指正~

一、 宏任务、微任务的基本概念

1.宏任务介绍

宏任务(Macro Task)是指由主线程上的事件触发器(Event Loop)进行调度的任务。宏任务包括但不限于如下几种情况:主线程上的代码块、setTimeout、setInterval、I/O 操作、DOM 事件等。

2.微任务介绍

微任务(Micro Task)是指由其他任务触发的任务。它们的优先级比宏任务更高,会在宏任务队列为空时立即执行。微任务包括但不限于如下几种情况:Promise 的回调函数、MutationObserver 的回调函数等。

3.宏任务、微任务发展及出现的原因:

JavaScript是典型的单线程(自上而下依次执行代码),但是,一个任务耗时过长,或多个任务需要执行时,势必导致线程阻塞,影响视图渲染效果。

在ES3以及以前的版本中,JavaScript本身没有异步任务能力,随着Promise的引入,JavaScript引擎自身也能够发起异步任务了。至此,JavaScript就可分为同步任务及异步任务;而JS又把异步任务做了进一步的划分,分为宏任务与微任务。

由于微任务执行快,一次性可以执行很多个,在当前宏任务执行后立刻清空微任务可以达到伪同步的效果,这对视图渲染效果起到至关重要的作用,这也是区分宏任务、微任务的原因。

 4.宏任务、微任务的基本类型

宏任务:

  • script(外层同步代码)

  • Ajax请求

  • setTimeout、setInterval

  • postMessage、MessageChannel

  • setImmediate(Node.js 环境)、I/O(Node.js 环境)

  • ...

微任务

  • Promise.then().catch() 和 .finally()

  • process.nextTick(Node.js 环境)

  • ...

二、 事件循环模型(Event Loop)

如上图,当同步代码执行完毕后,就会执行所有的宏任务,宏任务执行完成后,会判断是否有可执行的微任务;如果有,则执行微任务,完成后,执行宏任务;如果没有,则执行新的宏任务,形成事件循环。

这只是图示宏任务及微任务的执行关系,那么,js在 Event Loop中究竟是如何调用方法去处理的呢?

  1. 我们写的代码,js会进行任务类型分配,根据类型放入不同的任务队列中;
  2. Event Loop 会根据执行时机,将需要执行的函数,压入事件调用堆栈中执行;
  3. 相同的宏任务,也会有不同的执行时机,(类似 setTimeout 的 time),Event Loop 会控制将需要执行的函数压入

总结:Event Loop 在压入事件时,都会判断微任务队列是否还有需要执行的事件:如果有,则优先将需要执行的微任务压入;没有,则依次压入需要执行宏任务!

切记,宏任务执行完毕后,都会判断是否还有需要执行的微任务!!!在复杂的事件中,该点经常会错!!!

切记,宏任务执行完毕后,都会判断是否还有需要执行的微任务!!!在复杂的事件中,该点经常会错!!!

切记,宏任务执行完毕后,都会判断是否还有需要执行的微任务!!!在复杂的事件中,该点经常会错!!!

三、 Promise、async和await 在事件循环中的处理

1.Promise:

new Promise 创建实例的过程是同步的哦!

 console.log(1);
 new Promise((resolve, reject) => {
    console.log(2);
 })
 console.log(3);
// 结果: 1 2 3

但是,Promise.then().catch().finally()中的回调,是微任务。

 console.log(1);
 new Promise((resolve, reject) => {
    console.log(2);
    resolve(); // 触发 then 回调
    // reject(); // 触发 catch 回调
 }).then(()=>{
    console.log('then')
 }).catch(()=>{
    console.log('catch')
}).finally(()=>{
    console.log('finally')
})
 console.log(3);
// 结果: 1 2 3 then finally

上图是菜鸟教程-JavaScript Promise 中对Promise的讲解,我们想一下为啥要这样设计:

我们假设Promise 不是立即执行的,会有什么后果?利用Promise,多是封装异步请求(Ajax),而请求不是立即请求的,还需要等待Promise 任务执行,那么我们就失去了网络请求的时效性,会导致页面等待渲染(因为我们上面提及的 Event Loop 会根据事件执行时机,选择将事件压入堆栈中,我们无法保证自己写的【不是立即执行Promise】什么时候执行)。

        2. async/await :

简单来说,async是通过Promise包装异步任务。

async function fun1() {
  console.log('fun1 start')
  await fun2(); // 等待 fun2 函数执行完成
  console.log('fun1 end')
}
async function fun2() {
  console.log('fun2 start')
  console.log('fun2 end')
}
fun1()
 
// 输出结果: fun1 start、fun2 start、fun2 end、fun1 end

遇到 await 则需要等待 await 后的代码执行完成后,在往下执行代码。因此,可以将 await 看作抢夺线程的标记,fun1 中,本来是同步执行的,但是 await 的出现,导致线程执行了 fun2 的代码后,再次回到await,往后执行。

同时,await后面的代码,会进入then微任务中!!!

同时,await后面的代码,会进入then微任务中!!!

同时,await后面的代码,会进入then微任务中!!!

async function fun1() {
  console.log('fun1 start')
  await fun2(); // 等待 fun2 函数执行完成
  console.log('我是 await 后面的代码')
  console.log('fun1 end')
}
async function fun2() {
  console.log('fun2 start')
  console.log('fun2 end')
}
fun1()
console.log('await 阻塞,导致 await后面代码进入 then 微任务')

这个知识点比较容易忽略,以为 await 回来后,直接继续执行后面的代码,这是不对的!

四、 process.nextTick在事件循环中的处理

process.nextTick是Node环境的变量,process.nextTick() 是一个特殊的异步API,其不属于任何的Event Loop阶段。事实上Node在遇到这个API时,Event Loop根本就不会继续进行,会马上停下来执行process.nextTick(),这个执行完后才会继续Event Loop。所以,nextTick和Promise同时出现时,肯定是process.nextTick() 先执行。

可以类比 Vue.$nextTick(),也是需要执行完这个函数后,才能继续Event Loop。

五、 典型案例

5.1 典型的宏任务、微任务

setTimeout(function () {
    console.log('1');
});
 
new Promise(function (resolve) {
    console.log('2');
    resolve();
})
  .then(function () {
      console.log('3');
  })
  .then(function () {
      console.log('4')
  });
        
console.log('5');

5.2 宏任务中包含微任务

setTimeout(function () {
    console.log('1');
    new Promise(function (resolve) {
        console.log('2');
        resolve();
    })
      .then(function () {
          console.log('3');
      })
    console.log('4');
});
 
console.log('5');

5.3 微任务中包含宏任务

console.log('1');
new Promise(function (resolve) {
    console.log('2');
    resolve();
})
  .then(function () {
      console.log('3');
      setTimeout(function () {
          console.log('4');
       })
      console.log('5');
  })
 
console.log('6');

5.4 async 宏任务

async function fun1() {
  console.log('fun1 start')
  setTimeout(function () {
      console.log('fun1 setTimeout');
  });
  await fun2();
  console.log('fun1 end')
}
 
async function fun2() {
  console.log('fun2 start')
  new Promise((resolve)=>{
      console.log('fun2 Promise')
      resolve()
  })
    .then(()=>{
        console.log('fun2 Promise then')
    })
  console.log('fun2 end')
}
 
fun1()

5.5 node 事件执行分析

console.log('1');
 
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})
 
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

5.6 综合案例

console.log('script start')
 
async function fun1() {
  console.log('fun1 start')
  process.nextTick(function() {
    console.log('fun1 process nextTick');
  })
  setTimeout(function () {
      console.log('fun1 setTimeout');
      new Promise(function (resolve) {
          console.log('fun1 Promise');
          resolve();
      })
        .then(function () {
            console.log('fun1 Promise then');
            setTimeout(function () {
                console.log('fun1 Promise then setTimeout');
             })
            console.log('fun1 Promise then end');
        })
  });
  await fun2();
  console.log('fun1 end')
}
 
async function fun2() {
  console.log('fun2 start')
  setTimeout(function () {
      console.log('fun2 setTimeout');
  });
  new Promise((resolve)=>{
      console.log('fun2 Promise')
      resolve()
  })
    .then(()=>{
        console.log('fun2 Promise then')
    })
  console.log('fun2 end')
}
 
fun1()
 
setTimeout(function() {
  console.log('setTimeout-000')
}, 0)
 
new Promise(resolve => {
  console.log('Promise')
  process.nextTick(function() {
    console.log('Promise process nextTick');
  })
  resolve()
})
  .then(function() {
    console.log('promise1')
  })
  .then(function() {
    console.log('promise2')
    process.nextTick(function() {
      console.log('promise2 process nextTick');
    })
  })
 
console.log('script end')

六、案例分析

6.1 典型的宏任务、微任务

 // 同步任务
 console.log('2'); // new promise 实例化过程
 console.log('5');
 // 
 // 将 setTimeout console.log('1'); 放入宏任务队列
 // 将Promise 的回调放入微任务队列
 // then  console.log('3');
 // then  console.log('4')
 
 // 先微任务
 console.log('3');
 console.log('4')
// 再宏任务
 console.log('1');
 
// 因此,输出结果: 2 5 3 4 1

6.2 宏任务中包含微任务

// 同步任务
console.log('5');
// 将 setTimeout 放入宏任务队列,此时,没有微任务执行,因此,开始执行setTImeout宏任务
console.log('1');
// new Promise 实例化 同步执行:
console.log('2');
// 将Promise.then 回调放入微任务
// 当前(setTimeout)的宏任务事件还没有执行完!!!
// 注意哈!!当前(setTimeout)的宏任务事件还没有执行完!!!,事件未跳出当前 Loop
console.log('4');
// 执行完宏任务,开始执行 微任务
console.log('3');
 
// 因此,结果为: 5 1 2 4 3

6.3 微任务中包含宏任务

 // 同步代码:
console.log('1');
// new Promise 
console.log('2');
console.log('6');
// 微任务:Promise.then
console.log('3');
console.log('5');
// 结束当前 Loop[有上个例子,这个就不难理解了]
// 开启宏任务
console.log('4');
 
// 因此,结果为:1 2 6 3 5 4

6.4 async 宏任务

 // fun1
console.log('fun1 start')
// 将setTimeout 放入宏任务队列
//  await fun2(); 进入 fun2
console.log('fun2 start')
//   new Promise
console.log('fun2 Promise')
// 将 then 放入微任务
console.log('fun2 end') // 当前任务队列
 
// 有微任务,先执行微任务
console.log('fun2 Promise then')
// 回到 await 处
console.log('fun1 end') // 当前 fun1 队列
console.log('fun1 setTimeout'); // 最后的宏任务

6.5 node 事件执行分析

// 从上往下:
console.log('1'); // 同步代码
//  setTimeout 宏任务1
//  process.nextTick 微任务1
console.log('7'); // new Promise
// Promise.then 微任务2
// setTimeout 宏任务2
// -- 开始执行微任务
console.log('6');
console.log('8')
 
// -- 开始宏任务1 
console.log('2');
//  process.nextTick 微任务!!!
console.log('4'); // new Promise
// Promise.then 微任务!!!
// 到此,当前宏任务已执行完毕,有微任务,需要先执行微任务
console.log('3');
console.log('5')
        
// 执行宏任务 2
console.log('9');
//  process.nextTick 微任务
console.log('11');// new Promise
// Promise.then 微任务!!!
console.log('10');
console.log('12')
 
// 因此,结果为:1 7 6 8 2 4 3 5 9 11 10 12

6.6 综合案例

// 这个案例,就应用了 await 导致的 then 微任务细节,我第一次分析也错了
// 还涉及了process.nextTick node 的执行时机优先
         
// 开始分析:
        console.log('script start')
        // fun1() 进入 fun1
        console.log('fun1 start')
        // 生成微任务 process.nextTick(fun1)
        // 生成 宏任务 setTimeout (fun1)
        await fun2(); // 进入 fun2
        console.log('fun2 start')
        // 生成宏任务 setTimeout (fun2)
        console.log('fun2 Promise') // new Promise
        // 生成 Promise.then 微任务
        console.log('fun2 end')
        // !!!此时,fun2 已经有返回值了,不需要等待 fun2 中的事件执行,回到 await 处,被标记了 await .then 的微任务
        // 因此,执行主任务
        console.log('Promise') // new Promise
        // 生成 Promise process.nextTick 微任务
        // 生成 Promise1.then 微任务
        // 生成 Promise2.then 微任务
        console.log('script end')
        /**
         * 分析微任务队列
         * 1. 第一个微任务:process.nextTick(fun1)
         * 2. fun2 Promise.then // 容易漏
         * 3. await .then 的微任务 !!!!!!!!!!!!!
         * 4. Promise process.nextTick 微任务
         * 5. Promise1.then 微任务
         * 6. Promise2.then 微任务
         *
        */
        // 根据 Node process 优先级,先执行 process
        console.log('fun1 process nextTick');
        console.log('Promise process nextTick');
        console.log('fun2 Promise then')
        // await.then微任务[await 后的所有代码,如果还有任务,具体再分析即可]
        console.log('fun1 end')
        console.log('promise1')
        console.log('promise2') // 执行到这,又生成新的 process.nextTick 微任务,又先执行
        console.log('promise2 process nextTick');
        // 没有微任务了,开始执行宏任务
        console.log('fun1 setTimeout');
        console.log('fun1 Promise'); // 生成新的 promise.then 微任务,当前宏任务已执行完成,开始执行微任务
        console.log('fun1 Promise then'); // 生成新的 宏任务 fun1 Promise then setTimeout
        console.log('fun1 Promise then end');
        /**
         * 此时,分析宏任务队列
         * 1.  第一个 是 fun2 setTimeout
         * 2.  setTimeout(function () { console.log('setTimeout-000') }, 0)
         * 3.  fun1 Promise then setTimeout
         * */
        // 因此, 依次执行宏任务
        console.log('fun2 setTimeout');
        console.log('setTimeout-000')
        console.log('fun1 Promise then setTimeout');

这个案例比较复杂,某些事件容易漏掉,因此,建议大家手动勾起来,每一个事件都对应到事件队列中,这个案例,考察两个点,一个是 await的处理及 node.process 的优先级。大家弄懂这个案例,出去面试,手撕这种题目应该不是问题了。

总结起来,宏任务与微任务的执行顺序可以归纳为以下几点:

  1. 当一个宏任务执行完毕后,会检查微任务队列中是否存在微任务。
  2. 如果存在微任务,则会依次执行微任务直到微任务队列为空。
  3. 然后再从宏任务队列中取出下一个宏任务进行执行。
  4. 这个过程会一直重复,直到宏任务队列和微任务队列都为空。

在实际开发中,我们常常会利用宏任务与微任务的执行顺序来进行任务的调度。通过将一些耗时较长的任务放在宏任务中,可以保证其他任务的及时执行;而将一些需要优先执行的任务放在微任务中,可以保证其优先级更高。

需要注意的是,宏任务与微任务的执行顺序是由浏览器的事件循环机制控制的,不同的浏览器可能存在一些差异。因此,在实际开发中,我们应该合理地安排宏任务与微任务的使用,避免出现一些不可预期的结果。

综上所述,宏任务与微任务的执行顺序是宏任务队列执行完毕之后依次执行微任务队列,然后再从宏任务队列中取出下一个宏任务进行执行。在实际开发中,我们可以根据这个执行顺序来合理地安排任务的执行,以达到更好的效果。

参考文章:

宏任务和微任务的执行顺序_微任务和宏任务的执行顺序-CSDN博客

宏任务与微任务执行顺序(超详细讲解)_宏任务和微任务谁先执行-CSDN博客

微任务和宏任务哪个先执行?_宏任务和微任务谁先执行-CSDN博客

例子出处:宏任务与微任务执行顺序(超详细讲解)_宏任务和微任务谁先执行-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/336704.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux内存管理:(九)内存规整

文章说明: Linux内核版本:5.0 架构:ARM64 参考资料及图片来源:《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址: zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 1. 引言 伙伴系统以页面为单位来管…

Pytest 测试框架与Allure 测试报告——Allure2测试报告-L3

目录: allure2报告中添加附件-图片 Allure2报告中添加附件Allure2报告中添加附件(图片)应用场景Allure2报告中添加附件(图片)-Python代码示例:allure2报告中添加附件-日志 Allure2报告中添加附件&#xff…

Linux的权限(3)

目录 文件类型 ​d目录文件 -普通文件 l链接文件 b块设备文件 p管道文件 c字符设备文件 文件权限 目录权限 umask 粘滞位 Q1umask权限默认值664/775 Q2"可执行性"权限 Q3"删除"权限 Q4怎么共享一批文件 【1】粘滞位 【2】添加交互人员到所…

第八讲_ArkTS装饰器(五)

ArkTS装饰器(五) 1. Watch装饰器1.1 Watch装饰器的特点1.2 Watch装饰器使用示例 2. ArkTS装饰器总结 1. Watch装饰器 Watch用于对状态变量的监听。如果需要关注某个状态变量的值是否改变,可以使用Watch为状态变量设置回调函数。 何为状态变…

基于DUP的网络聊天室

基于UDP的网络聊天室的使用&#xff08;select&#xff09;完成的服务器端 #include<head.h> typedef struct de {char name[10];struct sockaddr_in cin;struct de* next; }*linklist; //创建节点 linklist a_creat() {linklist p(linklist)malloc(sizeof(struct de));…

Flink SQL

Flink SQL 来源&#xff1a;B站尚硅谷 sql-client准备 Table API和SQL是最上层的API&#xff0c;在Flink中这两种API被集成在一起&#xff0c;SQL执行的对象也是Flink中的表&#xff08;Table&#xff09;&#xff0c;所以我们一般会认为它们是一体的。Flink是批流统一的处理…

LSTM学习笔记

上一篇文章中我们提到&#xff0c;CRNN模型中用于预测特征序列上下文的模块为双向LSTM模块&#xff0c;本篇中就来针对该模块的结构和实现做一些理解。 Bidirectional LSTM模块结构如下图所示&#xff1a; 在Pytorch中&#xff0c;已经集成了LSTM模块&#xff0c;定义如下&…

Spring成长之路—Spring MVC

在分享SpringMVC之前&#xff0c;我们先对MVC有个基本的了解。MVC(Model-View-Controller)指的是一种软件思想&#xff0c;它将软件分为三层&#xff1a;模型层、视图层、控制层 模型层即Model&#xff1a;负责处理具体的业务和封装实体类&#xff0c;我们所知的service层、poj…

【开源】基于JAVA语言的中学生家校互联系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生管理模块2.2 课堂表现模块2.3 考试成绩模块2.4 家校留言模块2.5 校园通知模块 三、系统设计3.1 用例设计3.2 实体类设计3.2.1 课堂表现实体类设计3.2.2 考试成绩实体类设计3.2.3 家校留言实体类设计3.2.4 校园通知实…

AWS 专题学习 P8 (ECS、EKS、Lambda、CloudFront、DynamoDB)

文章目录 什么是 Docker&#xff1f;操作系统上的 DockerDocker 镜像存储Docker vs. Virtual MachinesDocker 入门AWS 中的 Docker Containers Management Amazon ECSEC2 Launch TypeFargate Launch TypeECS 的 IAM RolesLoad Balancer IntegrationsData Volumes (EFS)ECS Serv…

HCIA——20应用层:C/S、P2P、peer

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…

产品经理学习-产品运营《用户运营策略》

⽤户画像与⽤户运营策略 什么是用户画像 对产品运营而言&#xff0c;用户画像就是对用户的各种特征贴上标签通过这些标签将用户分成不同的用户群体 为用户提供有针对性的服务。 制作用户画像是为了专注和精准 使产品的服务对象更加聚焦&#xff0c;更加专注&#xff1b;根据产…

红包封面免费送1000个,你设计,我出额度

相信最近大家或多或少都知道了吧&#xff0c;腾讯又又又给大家&#xff0c;准确的说是给一年勤奋的公众号/视频号博主一个福利 根据不同博主的粉丝、更新频度以及作品质量&#xff0c;给力博主们免费制作红包封面的福利 比如我这个号&#xff0c;有6000额度 那这6000个&#…

Python武器库开发-武器库篇之Fofa-API使用(四十六)

Python武器库开发-武器库篇之Fofa-API使用(四十六) FOFA&#xff08;FOcus Observation of Futures Assets&#xff09;是一款专业的网络资产搜索引擎&#xff0c;旨在帮助企业发现和评估网络上的潜在安全风险。FOFA的基本原理是通过搜索引擎的方式&#xff0c;按照关键词对互…

Civil 3D安装教程,免费使用,带安装包和工具,一分钟轻松搞的安装

前言 Civil 3D是一款面向基础设施行业的建筑信息模型&#xff08;BIM&#xff09;解决方案。它为基础设施行业的各类技术人员提供了强大的设计、分析以及文档编制功能&#xff0c;广泛适用于勘察测绘、岩土工程、交通运输、水利水电、市政给排水、城市规划和总图设计等众多领域…

【Spring 篇】MyBatis核心配置文件解密:数据之门的守护精灵

欢迎来到MyBatis的幕后花絮&#xff0c;今天我们将深入解析MyBatis的核心配置文件&#xff0c;这个神秘的数据之门的守护精灵。这份配置文件是连接你的应用程序和数据库之间的纽带&#xff0c;也是整个MyBatis舞台背后的幕后工作者。在这篇博客中&#xff0c;我们将揭开核心配置…

ES框架详解

ES框架详解 1、全文检索的介绍 ​ 那么对于一般的公司&#xff0c;初期是没有那么多数据的&#xff0c;所以很多公司更倾向于使用传统的数据库&#xff1a;mysql&#xff1b;比如我们要查找关键字”传智播客“&#xff0c;那么查询的方式大概就是:select * from table where …

vue3项目eslint配置、配置prettier(格式化配置)

文章链接: 全部配置链接 第一步:eslint配置、配置prettier(代码格式化):点击链接 (1) .eslint.cjs—eslint配置文件 (2).eslintignore—校验忽略文件 (3).prettierrc.json添加规则 (4).prettierignore忽略文件 prettierrc规范说明: npm install -D eslint-plugin-import…

修复uni-simple-router@2.0.7版本query参数null的bug

问题&#xff1a;query参数为null或者为空时&#xff0c;插件内部参数校验问题导致的会报错&#xff1a;TypeError: Cannot convert undefined or null to object at Function.keys 源码修改如下&#xff1a; 通过打补丁的方式修复query参数类型校验问题 1. 安装patch-packag…

SPI 动态服务发现机制

SPI&#xff08;Service Provier Interface&#xff09;是一种服务发现机制&#xff0c;通过ClassPath下的META—INF/services文件查找文件&#xff0c;自动加载文件中定义的类&#xff0c;再调用forName加载&#xff1b; spi可以很灵活的让接口和实现分离&#xff0c; 让API提…