,,前端js中的事件循环eventloop机制详解

,,前端js中的事件循环eventloop机制详解

本文主要介绍前端js中eventloop机制的相关信息。通过示例代码进行了非常详细的介绍,对大家学习或使用js有一定的参考价值。和有需要的朋友一起学习吧。

前言

我们知道js是单线程执行的,那么如何处理异步代码js呢?例如,下面的代码是如何输出的:

console . log(1);

setTimeout(function() {

console . log(2);

}, 0);

新承诺(功能(解决){

console . log(3);

resolve(date . now());

}).then(function() {

console . log(4);

});

console . log(5);

setTimeout(function() {

新承诺(功能(解决){

console . log(6);

resolve(date . now());

}).then(function() {

console . log(7);

});

}, 0);

在不运行的情况下,可以先猜测最终输出,再展开我们要说的内容。

1. 宏任务与微任务

根据我们多年编写ajax的经验,js应该是按照语句的顺序执行的。在异步的情况下,它会发起一个异步请求,然后向下执行,在异步结果返回后再执行。但是他如何在内部管理这些任务呢?

在js中,任务分为宏任务和微任务。这两个任务分别维护一个队列,都是先入先出策略执行!同步任务都是在宏任务上执行的。

宏主要包括:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js环境)。

微任务主要有:Promise.then、MutationObserver、process.nextTick(Node.js环境)。

具体操作步骤如下:

从宏任务的头部取出一个任务进行执行;

如果在执行过程中遇到微任务,将其添加到微任务的队列中;

宏任务完成后,微任务队列中是否有任务,如果有,则出去逐个执行,直到执行完毕;

GUI渲染;

返回步骤1,直到宏任务完成;

这四个步骤构成了事件的循环检测机制,我们称之为eventloop。

回到我们上面说的代码:

console . log(1);

setTimeout(function() {

console . log(2);

}, 0);

新承诺(功能(解决){

console . log(3);

resolve(date . now());

}).then(function() {

console . log(4);

});

console . log(5);

setTimeout(function() {

新承诺(功能(解决){

console . log(6);

resolve(date . now());

}).then(function() {

console . log(7);

});

}, 0);

执行步骤如下:

执行log(1)并输出1;

遇到setTimeout时,将回调代码log(2)添加到宏任务中执行;

执行console.log(3)将日志(4)添加到微任务中;

执行log(5)并输出5;

遇到setTimeout时,将回调代码log(6,7)添加到宏任务中;

执行完宏的一个任务后,检查微任务队列中是否有任务。有一个微任务日志(4)(步骤3中添加的),执行输出4;

取出下一个宏任务日志(2)执行,输出2;

宏观任务的一个任务完成后,检查微观任务队列中是否有任务,没有;

取出下一个要执行的宏任务,执行log(6),然后将log(7)添加到微任务中;

宏任务执行后,有一个微任务日志(7)(在步骤9中添加),执行输出7;

所以最后输出的顺序是:1,3,5,4,2,6,7;

我们在Promise.then中实现了一个稍微耗时的操作,这个步骤看起来会更明显:

console . log(1);

var start=date . now();

setTimeout(function() {

console . log(2);

}, 0);

setTimeout(function() {

console.log(4,date . now()-start);

}, 400);

Promise.resolve()。then(function() {

var sum=函数(a,b) {

退货数量(a)数量(b);

}

var RES=[];

for(var I=0;i5000000i ) {

var a=math . floor(math . random()* 100);

var b=math . floor(math . random()* 200);

res.push(sum(a,b));

}

RES=RES . sort();

console . log(3);

})

在Promise.then中,老师组成一个由500万个随机数组成的数组,然后对数组进行排序。运行这段代码显示,立即输出1,过一会儿输出3,然后输出2。不管等多久输出3,3之后都会输出2。这也印证了eventloop中的第三步,需要等到所有的微任务完成后,才能开始下一个宏任务。

同时,这段代码的输出非常有趣:

setTimeout(function() {

console.log(4,date . now()-start);//4,1380输出的时间差随着电脑的状态而变化。

}, 400);

本来应该是400ms后输出的,但是因为前一个任务耗时太多,后续任务只能延迟。也可以解释为setTimeout和setInterval的延迟不准确。这两种方法只能在400ms后的宏任务中使用,但具体执行时间还是要看线程是否空闲。如果前一个任务中有耗时的操作,或者涉及到无限的微任务,那么下一个任务的执行就会被阻塞。

2. async-await

从上面的代码也可以看出,Promise.then中的代码属于微服务,那么如何执行async-await的代码呢?例如,下面的代码:

函数A() {

return promise . resolve(date . now());

}

异步函数B() {

console . log(math . random());

let now=wait A();

console.log(现在);

}

console . log(1);

b();

console . log(2);

实际上,async-await只是Promise generator的一个语法上的糖。我们重写了上面的代码,使其更加清晰:

函数B() {

console . log(math . random());

答()。然后(函数(现在){

console.log(现在);

})

}

console . log(1);

b();

console . log(2);

所以我们可以理解输出的顺序:1,0,0(随机数),2,2(时间戳);18869.4084000000005

3. requestAnimationFrame

RequestAnimationFrame也属于异步执行的方法,但是我的任务既不是宏任务也不是微任务。根据MDN中的定义:

Window.requestAnimationFrame()告诉浏览器——你要执行一个动画,并要求浏览器在下次重绘前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该函数将在浏览器下一次重绘之前执行。

RequestAnimationFrame在GUI渲染之前执行,但在微服务之后执行。但requestAnimationFrame不一定要在当前帧中执行,浏览器可以根据当前策略决定执行哪一帧。

4. 总结

我们要记住最重要的两点:js是单线程和eventloop的循环机制。

好了,这就是本文的全部内容。希望这篇文章的内容对你的学习或工作有一定的参考价值。谢谢你的支持。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • 关于js中的全等和不全等,等于和不等于问题的关系,,关于JS中的全等和不全等、等于和不等于问题
  • Vue项目启动,nodejs启动vue项目,如何启动一个Vue.js项目
  • vue双向绑定和单向绑定,vue.js 双向绑定,Vue双向绑定详解
  • vue事件修饰符和按键修饰符,vue事件绑定修饰符都有哪些,Vue.js 事件修饰符的使用教程
  • vue中-model的作用,Vue中的v-model指令的作用是-,vue.js 实现v-model与{{}}指令方法
  • vue2.0双向绑定原理,vue.js 双向绑定
  • vue2.0双向绑定原理,vue.js 双向绑定,深入理解vue.js双向绑定的实现原理
  • vue.js路由跳转,vue-router路由跳转,Vue路由跳转的4种方式小结
  • vue.js打包,vue前端如何打包,详解Vue项目的打包方式
  • vue.js前后端分离,vue前后端分离web项目,Vue之前端体系与前后端分离详解
  • vue.js 遍历数组,vue中遍历数组中的一个对象中的值
  • vue.js 遍历数组,vue中遍历数组中的一个对象中的值,Vue中遍历数组的新方法实例详解
  • UglifyJsPlugin,,Uglifyjs(JS代码优化工具)入门 安装使用
  • seajs教程,seajs还有人用吗,Sea.JS知识总结
  • require的用法js,require.js
  • 留言与评论(共有 条评论)
       
    验证码: