基础介绍

Stack 栈

一种先入后出的数据结构。

两个基本操作: 推入,弹出

Queue 队列

一种先入先出的数据结构

操作: 入队,出队

两种任务: 同步任务,异步任务

同步任务: 在调用栈中等待主线程依次执行。

  console.log('sync');

异步任务:结果不会立即返回,一般会有一个回调函数来处理返回结果。

  setTimeout(() => {
console.log('async');
}, 1000);

对于Javascript的疑惑

  • 什么是JavaScript?

    • answer: Javascript 是一个单线程脚本语言。

      单线程的运行环境,它有且只有一个调用栈,它同时只能够做一件事。
  • 那问题来了,如果使用Javascript执行上面的异步任务,那我们就需要等待它 1000ms 吗?如果这个异步任务是操作某个dom元素,是否会和用户同时操作同一个DOM元素,从而造成竞态问题?

    我们开始探究

我们称 Javascript 单线程的运行环境为主线程:

之所以叫主线程是因为很多东西在它上面运行,包括 JavaScript 和 样式渲染,也是DOM存在的地方。

但在我们进行渲染,接口请求和某些用户交互时,需要等待。这样它们就会造成阻塞。

所以,但是我们还是希望有其他的现场,用来处理网络,编码解码或是监听输入设备。

当这些设备完成了任务后,会把信息转交回主线程。实际上,是事件循环在指导这一切。

Event Loop

但是,我们在讲解 event loop 之前,先了解一下调用栈和任务队列

调用栈 (call stack)

所有的同步任务都在主线程上执行,形成一个执行栈。只有等待栈被清空,它才能执行下一个任务。

function multiply(a, b) {
return a*b;
}
function square(n) {
return multiply(n, n);
}
function printSquare(n) {
var squared = square(n);
console.log(squared);
}
printSquare(4);

调用栈是一个记录当前程序所在位置的数据结构,如果当前进入了某个函数,这个函数就会被放入栈中。如果当前离开了某个函数,这个函数就会被弹出栈外,这是栈所做的事。

使用动画可能更加生动:

而等待异步任务将会造成阻塞,幸运的是,浏览器提供了一些 JS 引擎不具备的功能:Web APIs。它可以帮助我们处理异步操作,它包括 DOM API,setTimeout,HTTP 请求 等等。

而web Api 处理完的异步操作如何回到 调用栈中呢?那就需要任务队列登场了。

任务队列 (callback queue)

只有异步任务有了结果,就会被放入“任务队列”中,在任务队列中进行排队,进入调用栈。

我们再看一段代码

setTimeout(() => {
console.log('setTimeout one');
}, 1000);
setTimeout(() => {
console.log('setTimeout two');
}, 1000);

如果有两个事件,每个事件都会成为一个todo 项放到队列中。

通过事件循环依次的去处理他们回调。就像这样:

事件循环 (Event Loop)

Event Loop的任务:连接任务队列和调用栈。

它不停的检查 调用栈 中是否还有任务在执行,如果没有,就检查任务队列,从中弹出一个任务,放入调用栈,循环往复。

回调被放入调用栈执行,得到结果后被弹出,只留下了一个 Hey!

当执行栈执行完毕时,会立刻先处理所以微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远比宏任务之前执行。

渲染

当我们考虑到渲染,事情可能就会更加复杂,我们可以把渲染看做另一个弯道。渲染发生在每一帧的开始,包括样式计算,布局和绘制。

因为事件循环会保证在渲染之前,Javascript会将任务执行完。所以,浏览器只能默默的看着你装逼,然而他只执行最后一行代码。

button.addEventListener('click',() => {
box.style.display = 'none';
box.style.display = 'block';
box.style.display = 'none';
box.style.display = 'block';
box.style.display = 'none';
box.style.display = 'block';
box.style.display = 'none';
box.style.display = 'block';
box.style.display = 'none';
});

再一些老的动画库中,人们喜欢使用setTimeout来绘制动画,如果更加了解 requestAnimationFrame,我相信他们将选择后者。

首先我们来对比一段代码

move() {
let x = 0;
let x1 = 0;
setInterval(() => {
x += 1;
this.timeoutX = { marginLeft: `${x}px` };
}, 16.6);
const animate = () => {
x1 += 1;
this.animationX = { marginLeft: `${x1}px` };
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}

动画结果:

requestAnimationFrame, setTimeout 同时执行时,setTimout 执行的频率更高一些,而RAF则和显示刷新频率一致,有固定的执行间隔。(这是其他大佬通过实验得来的,我上面的测试,可能是因为电脑每秒的刷新频率不足60帧)

所以使用setTimeout 来模拟帧率十分不准确,可能会出现下图的情况。

如果使用requestAnimationFrame 一切就显得井然有序多了

测试一下

彻底搞懂浏览器Event-loop - 前端进阶 - SegmentFault 思否 --你可以通过这篇文章底部的代码进行测试,你对 event loop 和任务执行顺序是否了解了。

参考

彻底搞懂浏览器Event-loop - 前端进阶 - SegmentFault 思否

动图学 JavaScript 之:事件循环(Event Loop) - 码力全开 - SegmentFault 思否

Jake Archibald: 在循环 - JSConf.Asia -- YouTube

菲利普·罗伯茨:到底什么是Event Loop呢?- YouTube

原本准备的 event loop 分享的更多相关文章

  1. javascript的event loop事件循环

    javascript的event loop事件循环 这是今天一个朋友发给我的一个面试题, 感觉还挺有意思的, 写个博客以供分享 先看看这个面试题目: 观察下面的代码,写出输出结果 console.lo ...

  2. 用大白话告诉你什么是Event Loop

    文章原文地址 前沿 从前有座山,山里有座庙,庙里有个小和尚在讲故事.讲什么呢?讲的是: 从前有座山,山里有座庙,庙里有个小和尚在讲故事.讲什么呢?讲的是: 从前有座山,山里有座庙,庙里有个小和尚在讲故 ...

  3. Atitit 解决Unhandled event loop exception错误的办法

    Atitit 解决Unhandled event loop exception错误的办法 查看workspace/.metadata/.log org.eclipse.swt.SWTError: No ...

  4. javascript运行模式:并发模型 与Event Loop

    看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和[朴灵评注]的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日 ...

  5. [译]Node.js - Event Loop

    介绍 在读这篇博客之前,我强列建议先阅读我的前两篇文章: Getting Started With Node.js Node.js - Modules 在这篇文章中,我们将学习 Node.js 中的事 ...

  6. Eclipse经常报Unhandled event loop exception的原因

    在公司的电脑上,Eclipse经常报Unhandled event loop exception 错误,非常频繁,通过搜索发现是因为电脑上安装了百度杀毒导致的.... 无语 另外 teamviewer ...

  7. Node.js 事件循环(Event Loop)介绍

    Node.js 事件循环(Event Loop)介绍 JavaScript是一种单线程运行但又绝不会阻塞的语言,其实现非阻塞的关键是“事件循环”和“回调机制”.Node.js在JavaScript的基 ...

  8. JavaScript 运行机制详解:再谈Event Loop

    原文地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一年前,我写了一篇<什么是 Event Loop?>,谈了我对Eve ...

  9. PYTHON ASYNCIO: FUTURE, TASK AND THE EVENT LOOP

    from :http://masnun.com/2015/11/20/python-asyncio-future-task-and-the-event-loop.html Event Loop On ...

随机推荐

  1. shell_backup_MySQL

    #!/bin/bash #可修改如下参数backup_filename=$(date +%Y%m%d%H%M%S)backup_tmp_dir=/data/backup/ip=10.0.1.182us ...

  2. python编程常用功能(随时添加)

    1 pandas查看DataFrame列或具体值数据类型 2 left join/right join/inner join的区别 3 df_series.value_counts() 4 删除dat ...

  3. scala编程(七)——内建控制结构

    几乎所有的 Scala 的控制结构都会产生某个值.这是函数式语言所采用的方式,程序被看成是计算值的活动,因此程序的控件也应当这么做.另外,指令式语言经常具有三元操作符(如 C,C++和 Java 的? ...

  4. winform显示word和ppt文档

    最近所做的项目中需要在Winform窗体中显示Office文档.刚开始就使用webBrowser控件实现的,但是后来发现这个控件在显示Office文档的时候有个限制:只支持Office2003之前的版 ...

  5. oracle ORA-01461 错误 can bind a LONG value only for insert into a LONG column

    我的ORACLE表里没有long字段,可是保存时报错:  ORA-01461 :仅可以为插入LONG列的LONG值赋值  本来我这张表里只有一个VARCHAR2(4000)的字段,一直没有这种错误发生 ...

  6. The Tower(ccpc吉林)

    http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1005&cid=867 #include<iostream> ...

  7. 同步linux系统时间

    Linux的时间分为System Clock(系统时间)和Real Time Clock (硬件时间,简称RTC). 系统时间:指当前Linux Kernel中的时间. 硬件时间:主板上有电池供电的时 ...

  8. SHELL小练习

    1.SHELL编程服务器IP修改脚本 脚本实现动态IP修改: 脚本实现静态IP修改: 实现IP地址输入判断正确性: IP地址修改成功判断&回滚: 2.SHELL编程Tomcat多实例管理脚本( ...

  9. win10安装CAD失败,怎么强力卸载删除注册表并重新安装

    一些搞设计的朋友在win10系统下安装CAD失败或提示已安装,也有时候想重新安装CAD的时候会出现本电脑windows系统已安装CAD,你要是不留意直接安装CAD,只会安装CAD的附件或者直接提示失败 ...

  10. 基于Docker 部署Jmeter + Grafana + InfluxDB 性能测试监控配置(亲测可用)

    工具介绍: InfluxDB:是一款用Go语言编写的开源分布式时序.事件和指标数据库,无需外部依赖.该数据库现在主要用于存储涉及大量的时间戳数据,如DevOps监控数据,APP metrics, lo ...