js中的事件执行顺序梳理

了解js的事件执行顺序,首先明白两组概念:

  • 同步任务/非耗时任务:指的是在主线程上排队执行的任务,只有前一个执行完毕才能执行后一个任务。

  • 异步任务/耗时任务:由js委托给宿主环境进行执行,执行完后会通知js主线程执行异步任务的回调函数。

同时呢,异步任务又分为宏任务和微任务:

  • 宏任务:异步ajax请求、setTimeout、setInterval、文件操作、其他
  • 微任务:Promise.then、.catch 和.finally,process.nextTick、其他

js的事件执行顺序是这样的:

js中的事件执行顺序梳理_第1张图片

语言描述:

js是单线程的,从上到下执行:

  • 从上到下执行,同步任务执行,异步任务扔到任务队列里等待。所有同步任务执行完,去到任务队列里。

  • 从上到下执行宏任务,new promise实例的时候是同步任务,所以promise里的语句立即执行,.then()里面的语句是微任务,放到微任务队列。每当有一个宏任务执行完毕就检查是否有微任务,有就把微任务先执行。一直这样循环。

    举个例子:两个人去银行办业务,排号,一个人办理完他需要的任务,然后业务员问他还有没有别的需求,如果这时候他提出了其他,还是会给他办理。等他的事情都办完了才能轮到下一个人办理业务。

举个例子分析一下

js中的事件执行顺序梳理_第2张图片

  1. 首先,从上往下看,console同步任务,执行,输出1;

  2. setTimeout异步任务,扔到消息队列;

  3. new一个Promise实例,立即执行,输出5。发现.then()里有微任务;

  4. 下面还是一个setTimeout异步任务,继续扔到消息队列;

  5. 主线程所有任务执行完了,检查一下是否有微任务,有,输出6;

  6. 开始处理第一个(2中的setTimeout)异步任务,输出2;new promise立即执行,输出3,发现.then()里面的微任务;

  7. 发现当前宏任务执行完毕,后面没有语句了,只有另一个宏任务,把微任务执行完再去处理,输出4;

  8. 执行第二个异步任务,输出7,new promise立即执行,输出8,发现.then()里面的微任务;执行完当前宏任务了,输出9

    正确顺序156234789

经过我上午对另一个例子的验证,发现process.nextTick()的执行优先于setTimeout

再来一个例子

这个里面是加了process.nextTick()的,还加了setTimeout(fn, 0)setImmediate

js中的事件执行顺序梳理_第3张图片

分析:

  1. 先执行同步任务,输出1;

  2. 第二个同步任务就是test函数,先执行,输出2;再执行new promise了,输出p1,检查到有一个.then()微任务。(!!!记住,我们现在在执行同步任务呢!!!),继续往下,一个异步任务,扔到任务队列。再走,输出3;又一个setImmediate,扔到队列;

  3. test执行完了,继续向下,输出4;

  4. 这时候同步任务都处理完了,轮到了这个微任务,输出p1.then;但是!!!nextTick是每当事件循环进行一次完整的行程时,在下一个事件循环滴答开始之前调用。在这里发现它的优先级高于.then,于是先输出nextTick;再输出P1.then;

    接下来就是setTimeout(fn, 0)和setImmediate的优先级问题了。建议参考https://www.cnblogs.com/dennisj/p/12550996.html这位博主的文章,总结出来这段就是setImmediatesetTimeout(fn, 0)哪个回调先执行,需要看他们本身在哪个阶段注册的,如果在定时器回调或者I/O回调里面,setImmediate肯定先执行。如果在最外层或者setImmediate回调里面,哪个先执行取决于当时机器状况。

  5. 他们等于都在最外层,取决于机器状况,但是我试了几次,都是定时器t1先执行的,可能因为setImmediate里运行的比较多,需要时间。所以输出t1;(这里并不确定,是基于结果的,欢迎指正)

  6. 然后进到setImmediate2里面,从上到下,输出setImmediate;输出s2;new promise实例,输出s2.p2,发现微任务,执行完当前函数(类似于前面的道理),输出s2end;

  7. 完成微任务,输出p2.then

    结果是 1 2 p1 3 4 nextTick P1.then t1 setImmediate s2 s2.p2 s2end p2.then

    js中的事件执行顺序梳理_第4张图片

js中的事件执行顺序梳理_第5张图片

还是这个图,我们在31行后加入一个setTimeout(time2, 0),打印的是新增的time。目的是验证同在setImmediate里的setImmediate和setTimeout的执行顺序。

  setImmediate(() *=>* {
​    console.log('setImmediate')
​    setImmediate(()*=>*{
		.......
​    })
​    setTimeout(time2, 0)
  })
  setTimeout(time1, 0)

}

可以发现,输出结果符合上面那位博主说的:如果在setImmediate`回调里面,哪个先执行取决于当时机器状况。

js中的事件执行顺序梳理_第6张图片

同样的,我也试了把最外层的setImmediate改成setTimeout,确实是setImmediate优先执行。

js中的事件执行顺序梳理_第7张图片

js中的异步任务

Events:javascript各种事件的执行都是异步任务
setTimeout、setInterval 定时器
queueMicrotask 执行微任务
Ajax
requestAnimationFrame 类似于定时器,但是是以每一帧为单位
fetch Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分
MutationObserver 创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。
Promise(但是promise会立即执行,.then里面的内容算作微任务)
async function


最后,发现我有篇笔记遗漏了没上传,刚好与这些有点点关系,传上来留着以后看
ES6模块化

默认导出 export default 只能使用一次,按需导出export可以使用多次

默认导入时接收名称可以自定义任何合法名称,按需导入的名字必须和按需导出的名字一致,按需导入可以用as重命名

默认导入和按需导入可以同时使用

如果只单纯想执行某个模块中的代码,不需要得到成员,可以不导出,直接用import导入文件路径就可以

Promise

解决回调地狱问题:嵌套太多,不方便维护代码。可读性差

  1. Promise是一个构造函数,new出来的Promise实例对象,代表一个异步操作
  2. Promise.prototype上包含一个.then()方法。每次promise实例都可以通过原型链prototype访问.then()方法
  3. .then()方法用来预先指定成功和失败的回调函数,成功的回调函数必选,失败可选

基于回调函数形式读取内容:node.js官方提供的fs模块仅支持以回调函数的方式读取文件,不支持Promise的调用方式。因此,需要先安装then-fs这个第三方包,从而支持我们基于Promise的方式读取文件内容;然后,导入这个模块;实例对象调用readFile方法并.then()设置成功函数

.then()可以链式调用,只要上一个结果是Promise实例,就可以继续用.then()方法

.catch()用来捕获错误

Promise.all()会发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步的.then操作(等待机制)

获取.then的两个实参:resolve、reject;失败 reject(err); 成功 resolve(data)

async/await

ES8的语法,简化Promise异步操作。在async/await出现前,只能用链式.then()方式处理Promise异步操作

读取的本来是一个promise实例对象,内容需要用.then获取,但是用了async和await之后就直接出现了结果。

方法内用到了await,方法外就需要用async修饰;在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行

EventLoop

js是单线程执行的编程语言,为防止某个耗时的任务导致程序假死的问题,js把待执行任务分两类:

  1. 同步任务/非耗时任务

    指的是在主线程上排队执行的任务,只有前一个执行完毕才能执行后一个任务

  2. 异步任务/耗时任务

    由js委托给宿主环境进行执行,执行完后会通知js主线程执行异步任务的回调函数

是单线程执行的编程语言,为防止某个耗时的任务导致程序假死的问题,js把待执行任务分两类:

  1. 同步任务/非耗时任务

    指的是在主线程上排队执行的任务,只有前一个执行完毕才能执行后一个任务

  2. 异步任务/耗时任务

    由js委托给宿主环境进行执行,执行完后会通知js主线程执行异步任务的回调函数

js主线程从任务队列中读取异步任务的回调函数,放到执行栈中依次执行。这个过程循环不断,这种运行机制又叫EventLoop

你可能感兴趣的:(前端重要知识详解,前端,javascript)