click事件在什么时候出发_剖析setTimeout和click点击事件的触发顺序

下面是一段非常简单的JavaScript代码

dianji

setTimeout(function () {

alert('timer handler')

}, 2000)

function test () {

document.addEventListener('click', function (e) {

alert('click handler')

}, false)

var startTime = new Date()

while ((new Date()).getTime() - startTime < 5000){}

}

但是当你点击这个按钮时,产生的效果可能会让你有些困惑。下面我们来看下:

页面打开2s内点击一次按钮

这段JavaScript代码当你在页面打开2s时间内点击一次按钮,效果是这样的:

页面卡住大约5s钟

大约5s后弹出 click handler

点击弹窗确认后,弹出 timer handler

当你继续再次点击页面中的按钮,此时依次发生:

页面卡住大约5s钟

大约5s后弹出 click handler 一次!

点击确认后又弹出 click handler 一次。

如果继续点击button按钮,会出现同样的效果,且 click handler 弹出的次数会依次增加

分析

分析这段代码来看,点击按钮后,代码执行会进入 test 函数, test函数中首先对 document 对象绑定上了一个 click 事件。然后执行了一个5s的死循环。

此时页面卡住就是因为这个死循环

ar startTime = new Date()

while ((new Date()).getTime() - startTime < 5000){}

这个死循环会导致js阻塞在这里. 在这5s时间内,2s的定时器其实在第2秒的时候已经定时完成,并把这个完成的事件放入到了任务队列中;而你在2秒之前点击的按钮这个click事件也被浏览器放入一个dom事件队列等待执行。

当5s死循环的时间过去,js引擎开始变成空闲,此时点击按钮触发的这个test处理器执行完毕,js引擎便从事件队列中取出 click 事件进行执行,当前元素没有订阅click那么就冒泡到订阅了该事件的document进行执行。(会继续冒泡到document。(本质上冒泡其实是: 浏览器取出dom事件中的click事件,然后从target元素开始往上找 看下是否整个网页中还有元素订阅了这个click事件)

由于在刚刚test函数执行期间,document对象上绑定上了 click 的监听,所以此时冒泡上来的 click 会触发document对象上的 click事件处理器, 因此弹出了 click handler.

当这个 click 冒泡完毕,所有的订阅者订阅的处理器都被完全处理完,js线程再次空闲,此时去查看任务队列中的任务,发现有个2s定时器的任务已经执行完毕,js开始执行定时器的回调函数,所以弹出了 time handler

当你第二次点击按钮,再次触发了 test 函数。 此时test函数内还是做了同样的事情,但是之前document上已经绑定了一个click的handler函数,所以第二次执行 test函数,会让 document对象的click处理器变成2个。 因此第二次点击按钮 click handler 会弹出2次

页面打开2s内点击一次按钮,然后第3s时点击页面空白处2次

这样操作的效果是这样的:

页面卡住大约5s钟

大约5s后弹出 'click handler'

弹出 'click handler' 第二次

弹出 'click handler' 第三次

弹出 'time handler'

分析

第2点之所以出现在第5点之前,在上文我们已经讲过原因了---总之,基本上是因为click触发的时刻确实就比timer触发的早,肯定要等click的handler都处理完再执行timer处理器。

但至于第3、4点为什么出现在5之前呢?这个跟2出现在5之前的原因就不一样了,因为用户在页面上的第二次和第三次点击是在2s钟之后了,此时timer定时器肯定已经完成了,但是触发 click handler 依然在 timer handler 之前。 这是为什么呢?

这主要是因为js获取任务来执行时, 点击事件的任务队列 要优先于 timer事件的任务队列。 具体可参考我的另外一篇文章 浏览器的单线程机制和事件循环

在页面卡住的5s时间内,用户在页面上点击的2次事件会放入比timer更优先的一个macroTask任务队列。由于js空闲时优先要把click事件这种更优先的macroTask任务执行完,直到任务队列为空。所以就出现了上面 click handler 要比 timer handler 更早弹出的效果。

心得

js中事件可以注册多个handler形成handlers. handlers类似于一个处理器的数组。事件触发后,该事件的handler处理器会被依次执行.

这里举个跟上面有点区别的例子:假如在某个handler执行的过程中,又给该事件增加了新的handler,那么新增的这个handler不能立即执行。

demo测试代码:

dianji

function test () {

alert('click handler 1');

/* test函数触发的过程中,又给按钮绑定了新的handler; 但本次handlers遍历执行的过程中,不会执行新加入的这个handler */

/* 因此,首次点击按钮, click handler2 不会弹出 */

document.querySelector('#test').addEventListener('click', function (e) {

alert('click handler 2')

}, false);

}

其实这里原理很简单:因为test元素对象上的事件handlers被触发执行的时候,类似于把数组拿出来遍历。你不可能把遍历数组和修改数组的逻辑同时运行。如:

let a = [1,2,3]

let count = 'x'

a.forEach((item, index) => {

console.log(item)

a.push(count + index)

})

console.log(a)

// 输出

// 1

// 2

// 3

// [ 1, 2, 3, 'x0', 'x1', 'x2' ]

除非你addEventListener的时候,添加到冒泡的上层元素上。即下面讲的第三点。

addEventListener 会给事件不断增加新的处理器handler

事件处理器handler在执行期间,事件还没有冒泡。此时还有机会给上层元素绑定事件处理器。

一个事件在冒泡过程中,要等所有订阅该事件的处理器都处理完毕,js才会去选择新的任务队列中的任务来执行。在事件触发后以及事件的冒泡过程中,会优先执行订阅了该冒泡事件的处理器,而不会去理会任务队列。

这一条原理很简单,只需知道:js在执行同一个dom事件的所有回调处理器的过程是同步的,占用js线程执行的即可。

在事件循环中 microTask 优先于 marcroTask执行,且macroTask中也有不同优先级的队列,例如dom事件便高于timer。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android里canvas视频帧,移动端用canvas截取视频封面,如何不截取第一帧,而是截取其它的帧?...

我在微信开发工具里截的图是可以的&#xff0c;但是在手机上截的图缺变成全透明的了。我猜是视频的第一帧的问题微信开发工具的截图手机的截图我的代码&#xff1a;JS&#xff1a;function captureImage(video) {var scale1var canvas document.createElement("canvas&qu…

python画正方形内切圆_python画出三角形外接圆和内切圆的方法

刚看了《最强大脑》中英对决&#xff0c;其中难度最大的项目需要选手先脑补泰森多边形&#xff0c;再找出完全相同的两个泰森多边形。在惊呆且感叹自身头脑愚笨的同时&#xff0c;不免手痒想要借助电脑弄个图出来看看&#xff0c;闲来无事吹吹牛也是极好的。 今天先来画画外接圆…

ar面部识别_Blippar公司加入实时面部识别技术 扫脸就能解锁个人AR简介

VR之家消息&#xff1a;近日&#xff0c;AR初创公司Blippar在其应用中加入了实时面部识别技术。据悉&#xff0c;利用这项新技术&#xff0c;用户通过智能手机摄像头扫脸&#xff0c;只要被扫对象已经存在AR简介&#xff0c;就能解锁这个人的个人资料。Blippar公司加入实时面部…

查看地区的ip段_「教程」CloudFlare 自选 IP优化网站速度

前言CloudFlare 官网虽然不提供 CNAME / AAAA / A 记录接入 CloudFlare 的 CDN &#xff0c;但是我们可以通过 CloudFlare Partner 免费使用 CNAME / A 记录接入 CloudFlare 。而我们正好利用 CloudFlare 使用 A 记录接入 CDN 的方式&#xff0c;自定义节点 IP &#xff0c;例如…

android手机可以设置屏幕锁定,安卓手机屏幕锁设置方法(九个点图案)

这里以三星S5368手机屏幕锁为例随着三星S5368手机系统功能愈来愈完善&#xff0c;性能愈来愈强劲&#xff0c;越来越多的三星S5368用户们都喜欢把一些重要的信息甚至隐私放在三星S5368手机里面&#xff0c;但是这就有可能会让别人看到&#xff0c;这样一来你的三星S5368里面的信…

python win10 连接hive_使用win10+python3.5+impyla 连接大数据平台hive表的步骤与问题解决...

环境硬件配置及Hadoop&#xff0c;Hive版本一、安装步骤pip install pure-saslDownloading https://pypi.tuna.tsinghua.edu.cn/packages/16/83/30eaf3765de898083 75a8358f9c15d45a3dd44ed26be991471abc0b4480b/pure_sasl-0.5.1-py2.py3-none-any.whlpip install thrift_sasl0…

python将excel表按地方拆分_Python将一个Excel拆分为多个Excel

本文实例为大家分享了Python将一个Excel拆分为多个Excel的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下 原始文档如下图所示将销售部门一、二、三科分别存为三个Excel 代码如下 # -*- coding: utf-8 -*- """ Created on Mon Jul 9 20:25:31 2018 au…

arduino麦轮转弯程序_麦克纳姆轮智能小车接线方案

折腾了好几天&#xff0c;实在搞不定了&#xff0c;决定上来社区求助。现在的硬件情况是这样的&#xff1a;- HM-GM37-3429霍尔传感器大载重电机&#xff0c;每个电机六条线&#xff0c;其中电机输入两个&#xff0c;霍尔编码器电源两个&#xff0c;编码器AB相两个- 四个电机&a…

python中range 函数_pythonrange,range函数的用法

当range()函数内填入第三个参数时&#xff0c;第三个参数表示百步长。函数语法&#xff1a;range(start,stop[,step])参数说明&#xff1a;start:计数从度start开始。默认是从0开始。例知如道range&#xff08;5&#xff09;回等价于range&#xff08;0&#xff0c;5&#xff0…

xss植入_网站xss漏洞的利用过程

XSS跨站脚本&#xff0c;是一种Web安全漏洞&#xff0c;有趣是是他并不像SQL注入等攻击手段攻击服务端&#xff0c;本身对Web服务器没有危害&#xff0c;攻击的对象是客户端&#xff0c;使用浏览器访问这些恶意地址的网民。这里就跟大家稍微讲解一下网站xss漏洞的利用过程。网站…

html制作状态栏数字时钟,html5 canvas制作15种数字时钟样式代码

特效描述&#xff1a;html5 canvas制作 数字时钟样式。html5 canvas数字时钟代码代码结构1. 引入CSS2. 引入JS3. HTML代码clockd1_{"indicate": true,"indicate_color": "#222","dial1_color": "#666600","dial2_color…

python出现的次数最多的元素_【Python 秘籍】序列中出现次数最多的元素

问题 怎样找出一个序列中出现次数最多的元素呢&#xff1f; 解决方案 collections.Counter 类就是专门为这类问题而设计的&#xff0c; 它甚至有一个有用的 most_common() 方法直接给了你答案。 为了演示&#xff0c;先假设你有一个单词列表并且想找出哪个单词出现频率最高。你…

华为申请注册鸿蒙商标,华为申请“鸿蒙商标”,企业注册商标有什么价值?

原标题&#xff1a;华为申请“鸿蒙商标”&#xff0c;企业注册商标有什么价值&#xff1f;国家知识产权局商标局网站显示&#xff0c;华为已申请“华为鸿蒙”商标。申请日期为2018年8月24日&#xff0c;注册公告日期为2019年5月14日&#xff0c;专用权限期是从2019年5月14日到2…

dabs是什么意思_cpdd是什么意思(网络语cpdd是什么梗啥意思)

随着网络的快速发展&#xff0c;抖音和微博这样的软件也是越来越火&#xff0c;因此很多流行语就随之诞生&#xff0c;特别是在抖音里&#xff0c;经常看到游戏相关的用语&#xff0c;比如桃酥和阿姨打LOL时候&#xff0c;就出现了很多高校的流行语&#xff0c;其中“cpdd”这个…

python coding utf-8_【转】怎么在Python里使用UTF-8编码

基本概念 在Python里有两种类型的字符串类型:字节字符串和Unicode的字符串&#xff0c;一个字节字符串就是一个包含字节列表。 当需要的时候&#xff0c;Python根据电脑默认的locale设置将字节转化成字符。 在Mac OX上默认的编码是UTF-8&#xff0c;但是在别的系统上&#xff0…

lisp6 暖通cad_(完整版)暖通CAD设计技巧1

暖通CAD设计技巧1.执行编辑命令&#xff0c;提示选择目标时&#xff0c;用矩形框方式选择&#xff0c;从左向右拖动光标&#xff0c;为"窗口Windows"方式&#xff0c;如果从右向左拖动光标&#xff0c;则为"交*Cross"方式。2.相对坐标输入点时&#xff0c;…

html5音乐播放器设计论文,基于微信小程序的音乐播放器设计和毕业论文

摘 要随着通信技术的发展和智能设备的普及&#xff0c;移动互联网在近两年发展迅猛&#xff0c;新兴的移动社交软件“微信”逐渐走进了手机用户的生活&#xff0c;深受全国数亿用户的欢迎。随着微信版本的不断更新&#xff0c;微信也从单纯的聊天应用逐变成媒体信息、游戏娱乐…

python递归_python3之递归

1、递归的特点 递归算法是一种直接或间接调用自身算法的过程&#xff0c;在计算机编程中&#xff0c;递归算法对解决一大类问题是十分&#xff0c;它往往使算法的描述简洁而且易于理解。 递归算法解决问题的特点&#xff1a; &#xff08;1&#xff09;递归就是在过程或函数里调…

什么原因导致芯片短路_PCB电路板短路的原因及解决方法-EDA/PCB-与非网

【导读】焊接短路(如&#xff1a;连锡)、PCB 短路(如&#xff1a;残铜、孔偏等)、器件短路、组装短路、ESD/EOS 击穿、电路板内层微短路、电化学短路(如&#xff1a;化学残留、电迁移)、其他原因造成的短路。首先&#xff0c;了解一下常见的电路板短路的种类&#xff1a;短路按…

html表格按钮相对位置不变,表格中如何使td或div相对定位在某一行上面

有个需求&#xff0c;就是点击表格某一行&#xff0c;上面要居中显示一组菜单。而列表需要有1列或多列不固定宽度&#xff0c;有的是百分比宽度&#xff0c;有的是固定宽度(就是传统的table用法&#xff0c;或者CSS3的Flex Box)小伙伴的实现是用table&#xff0c;js算出距表头的…