erik

艾瑞可erik

  • 主页
  • 归档
文章 (264) 手册 工具 友链 关于我
erik

艾瑞可erik

  • 主页
  • 归档

深入理解JavaScript定时机制

2015-01-07
字数统计: 2.4k字   |   阅读时长: 8分   |  本文总阅读量43次

容易欺骗别人感情的JavaScript定时器 JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如

1
2
3
4
setTimeout(function() {
alert('你好!');
}, 0);
setInterval(callbackFunction, 100);

认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行. 这里设成0毫秒,理所当然就立即被执行了. 同理对setInterval的callbackFunction方法每间隔100毫秒就立即被执行深信不疑! 但随着JavaScript应用开发经验不断的增加和丰富,有一天你发现了一段怪异的代码而百思不得其解:

1
2
3
4
5
div.onclick = function(){
setTimeout(function() {
document.getElementById('inputField').focus();
}, 0);
};

既然是0毫秒后执行,那么还用setTimeout干什么, 此刻, 坚定的信念已开始动摇. 直到最后某一天 , 你不小心写了一段糟糕的代码:
1
2
3
4
5
6
7
8
setTimeout(function() {
while (true) {
}
}, 100);
setTimeout(function() {
alert('你好!');
}, 200);
setInterval(callbackFunction, 200);

第一行代码进入了死循环,但不久你就会发现,第二,第三行并不是预料中的事情,alert问候未见出现,callbacKFunction也杳无音讯! 这时你彻底迷惘了,这种情景是难以接受的,因为改变长久以来既定的认知去接受新思想的过程是痛苦的,但情事实摆在眼前,对JavaScript真理的探求并不会因为痛苦而停止,下面让我们来展开JavaScript线程和定时器探索之旅! 拔开云雾见月明 出现上面所有误区的最主要一个原因是:潜意识中认为,JavaScript引擎有多个线程在执行,JavaScript的定时器回调函数是异步执行的. 而事实上的,JavaScript使用了障眼法,在多数时候骗过了我们的眼睛,这里背光得澄清一个事实: JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序. JavaScript引擎用单线程运行也是有意义的,单线程不必理会线程同步这些复杂的问题,问题得到简化. 那么单线程的JavaScript引擎是怎么配合浏览器内核处理这些定时器和响应浏览器事件的呢? 下面结合浏览器内核处理方式简单说明. 浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.假如某一浏览器内核的实现至少有三个常驻线 程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,这些异步线程都会产 生不同的异步事件,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.虽然每个浏览器内核实现细节不同,但这其中的 调用原理都是大同小异. Js线程图示 由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发 器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线 程关系,这些任务得进行排队,一个接着一个被引擎处理. 上图t1-t2..tn表示不同的时间点,tn下面对应的小方块代表该时间点的任务,假设现在是t1时刻,引擎运行在t1对应的任务方块代码内,在这个时间点内,我们来描述一下浏览器内核其它线程的状态. t1时刻: GUI渲染线程: 该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行.本文虽然重 点解释JavaScript定时机制,但这时有必要说说渲染线程,因为该线程与JavaScript引擎线程是互斥的,这容易理解,因为 JavaScript脚本是可操纵DOM元素,在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了. 在JavaScript引擎运行脚本期间,浏览器渲染线程都是处于挂起状态的,也就是说被”冻结”了. 所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来. GUI事件触发线程: JavaScript脚本的执行不影响html元素事件的触发,在t1时间段内,首先是用户点击了一个鼠标键,点击被浏览器事件触发线程捕捉后形成 一个鼠标点击事件,由图可知,对于JavaScript引擎线程来说,这事件是由其它线程异步传到任务队列尾的,由于引擎正在处理t1时的任务,这个鼠标 点击事件正在等待处理. 定时触发线程: 注意这里的浏览器模型定时计数器并不是由JavaScript引擎计数的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态就计不了时,它必须依赖外部来计时并触发定时,所以队列中的定时事件也是异步事件. 由图可知,在这t1的时间段内,继鼠标点击事件触发后,先前已设置的setTimeout定时也到达了,此刻对JavaScript引擎来说,定时触发线程产生了一个异步定时事件并放到任务队列中, 该事件被排到点击事件回调之后,等待处理. 同理, 还是在t1时间段内,接下来某个setInterval定时器也被添加了,由于是间隔定时,在t1段内连续被触发了两次,这两个事件被排到队尾等待处理. 可见,假如时间段t1非常长,远大于setInterval的定时间隔,那么定时触发线程就会源源不断的产生异步定时事件并放到任务队列尾而不管它 们是否已被处理,但一旦t1和最先的定时事件前面的任务已处理完,这些排列中的定时事件就依次不间断的被执行,这是因为,对于JavaScript引擎来 说,在处理队列中的各任务处理方式都是一样的,只是处理的次序不同而已. t1过后,也就是说当前处理的任务已返回,JavaScript引擎会检查任务队列,发现当前队列非空,就取出t2下面对应的任务执行,其它时间依此类推,由此看来: 如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务,在任务没返回前队列中的其它任务是没法被执行的. 相信您现在已经很清楚JavaScript是否可多线程,也了解理解JavaScript定时器运行机制了,下面我们来对一些案例进行分析: 案例1:setTimeout与setInterval
1
2
3
4
5
6
7
8
setTimeout(function() {
/\* 代码块... */
setTimeout(arguments.callee, 10);
}, 10);

setInterval(function(){
/*代码块... */
}, 10);

这两段代码看一起效果一样,其实非也,第一段中回调函数内的setTimeout是JavaScript引擎执行后再设置新的setTimeout 定时, 假定上一个回调处理完到下一个回调开始处理为一个时间间隔,理论两个setTimeout回调执行时间间隔>=10ms .第二段自setInterval设置定时后,定时触发线程就会源源不断的每隔十秒产生异步定时事件并放到任务队列尾,理论上两个setInterval 回调执行时间间隔<=10. 案例2:ajax异步请求是否真的异步? 很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步? 其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行 onreadystatechange所设置的函数. 转帖地址:http://www.9demo.com/archives/341

本文作者: 艾瑞可erik
本文链接: https://erik.xyz/2015/01/07/shen-ru-li-jie-javascript-ding-shi-ji-zhi/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
赏

一只PHP开发的程序猿,偶尔搞搞摄影、画画、写作、顺便睡觉。

支付宝
微信
  • js
  • javascript
  • 转载

扫一扫,分享到微信

微信分享二维码
为 MySQL 增加 HTTP/REST 客户端:MySQL UDF 函数 mysql-udf-http 1.0 发布
14条改善jQuery代码的技巧
0 条评论
未登录用户
支持 Markdown 语法

来做第一个留言的人吧!

艾瑞可erik·导航 | 算法演示 | postwoman | slim | zola | layui
© 2014-2025 艾瑞可erik | 粤ICP备2020136226号-1 | 粤公网安备 粤公网安备 44030602005398号
本站总访问量88222次 本站访客数72172人次
  • 文章
  • 手册
  • 工具
  • 友链
  • 关于我

tag:

  • 日志
  • 工具
  • jquery
  • jquery插件
  • php扩展
  • php技巧
  • php类库
  • php资源
  • js
  • css
  • php
  • web
  • 代码
  • 压缩
  • php服务器
  • 随笔
  • php实例
  • 说说
  • 趣闻
  • 转载
  • php库
  • nginx
  • 互联
  • 项目实战
  • javascript
  • php应用
  • 浮点
  • 漏洞
  • 负载均衡
  • kali
  • kali安装
  • http
  • http服务器
  • 农业系统
  • 系统设计
  • 克莱姆法则
  • 行列式
  • n阶行列式
  • 支付系统
  • 支付
  • apache优化
  • apache隐藏index
  • nginx优化
  • nginx隐藏index
  • centos
  • linux
  • 日常
  • seo
  • 优化
  • 摘要
  • 文章
  • 游记
  • ca证书
  • 证书生成
  • 二战
  • 二战熊
  • 西伯利亚熊
  • centos软件
  • yum仓库
  • 软件
  • centos安装chromium报错
  • chromium安装报错
  • svn
  • 代码提交
  • deb
  • deb/rpm互转
  • deb转rpm
  • rpm互转
  • centos7安装steam
  • centos安装steam
  • centos安装吃鸡steam
  • linux安装steam
  • steam安装
  • centos软件安装
  • centos6.5
  • linux系统
  • centos7安装Redis Desktop Manager
  • centos7安装redis桌面
  • centos安装redis桌面
  • linux安装centos7安装Redis Desktop Manager
  • Redis Desktop Manager
  • redis桌面
  • centos7
  • centos7-wine
  • wine
  • wine安装
  • root密码
  • root密码重置
  • 忘记root密码
  • memcache
  • memcached
  • 生活手记
  • 艾瑞可erik
  • 程序员
  • 开源云
  • 容器
  • cncf
  • 监控
  • composer
  • composer部署
  • 内网部署composer
  • cphalcon
  • cphalcon报错
  • css中的em
  • 响应式字体
  • 响应式布局样式
  • proxy代理搭建
  • 代理服务器搭建
  • proxy服务器
  • 查找
  • 排序
  • 快速排序
  • 冒泡排序
  • 二分查找
  • datahub
  • datahub安装
  • deepin
  • emergency
  • emergency mode
  • deepin黑屏
  • 清理系统
  • 清理c盘
  • dns
  • 域名监测
  • 网站监测
  • docker
  • php安装
  • 杂谈
  • ecshop
  • 框架
  • beego数据分页
  • 分页
  • elasticsearch
  • elasticsearch搭建
  • elasticsearch集群
  • phone
  • 手机
  • 新闻
  • 免费
  • jenkis
  • jenkis教程
  • 随笔吐槽
  • 算法
  • ping
  • ping服务器
  • 各大网站ping
  • 搜引擎ping服务器
  • go获取ip
  • go中pdf生成
  • go中限流
  • go对接快递签名
  • go时间获取
  • go类型转换
  • 微服务
  • go-zero
  • rpc
  • go加密
  • go解密
  • 归
  • 吐槽
  • hadoop
  • hadoop2.8.0
  • hadoop安装教程
  • hadoop安装详细教程
  • hadoop教程
  • hadoop部署
  • php大全
  • php资料
  • hadoop3
  • hadoop配置
  • log4j2
  • 数据库
  • hbase安装教程
  • hbase
  • http1.1
  • http2.0
  • 会话
  • 会话原理
  • hyperf
  • 杂录
  • 新冠肺炎
  • springboot
  • springboot内网部署
  • linux恢复
  • linux误删
  • linux命令
  • linux命令汇总
  • jenkins
  • jetbtrains
  • phpstorm
  • 搜索引擎
  • 图片
  • 素材
  • jq
  • jq侧边导航
  • 侧边导航
  • js判断浏览器
  • js判断浏览器版本
  • 判断浏览器
  • 浏览器版本判断
  • 获取浏览器信息
  • kali右键汉化
  • kali桌面右键汉化
  • kali右键创建文件
  • 区块链
  • lanmp
  • php环境独立配置
  • 服务器
  • 劳动纠纷
  • 追缴工资
  • 申请仲裁
  • flash
  • 表单
  • linux报错
  • linux中update-command-not-found
  • linux运行命令报错
  • web前端
  • web优化
  • 撮合算法
  • 撮合
  • php撮合算法
  • maven搭建库
  • maven
  • maven内网库
  • 高级缓存配置
  • mongodb
  • mongodb权限
  • 可穿戴设备
  • mysql
  • 分库分表
  • mysql应对千万级
  • mysql瓶颈
  • mysql瓶颈解决办法
  • redis
  • 数据一致性
  • mysql消息
  • mysql队列
  • mysql高并发
  • mysql存储
  • mysql引擎
  • mysql数据表设计选择
  • mysql监控
  • mysql性能
  • 内网支付
  • 内网穿透
  • 支付接口本地化开发
  • 本地挂网
  • 穿透
  • go
  • new和make的区别
  • 红包算法
  • 深圳劳动法服务部门
  • 非关系型数据库
  • onethink
  • oop
  • php管理系统
  • 开放接口开发
  • openresty
  • openvas
  • openvas安装
  • php变量
  • php超级全局变量
  • php超级变量
  • php基本类型
  • php数据类型
  • php对接微信支付
  • 微信支付
  • 微信支付回调
  • php设计模式
  • php函数
  • php随机数
  • php获取闰年
  • 闰年.php时间
  • php环境
  • php集成环境
  • 服务器集成环境
  • 数组函数
  • 数组排序函数
  • php数学函数
  • php面试题
  • php面向对象
  • 面向对象
  • php-zookeeper
  • zookeeper3.5.5
  • php-zookeeper扩展
  • php串口开发
  • php倒计时
  • php时间
  • 倒计时
  • 计算时间
  • PHP数组
  • 字符串函数
  • 排序函数
  • php的SPL
  • SPL手册
  • PHP算法
  • php递归
  • 递归
  • phpunit
  • phpunit安装
  • php过滤
  • 过滤
  • foreach
  • foreach报错
  • php中foreach报错
  • php中if
  • php中if判断
  • php的if
  • php字符串
  • php7中sphinx
  • php7中sphinx扩展
  • sphinx扩展
  • python
  • python库
  • a标签
  • a标签虚线
  • 虚线框
  • R语言
  • 数据随机化
  • redis总结
  • redis命令
  • redis监控
  • redis锁
  • redis分布式锁
  • 任意金额输入
  • 10元、5元、2元
  • 队列
  • 栈
  • 顺序表
  • 链表
  • 数据结构
  • 线性结构
  • 浏览器禁止操作视频
  • 禁止视频
  • js编辑
  • runjs
  • 在线编辑
  • 响应慢
  • 页面优化
  • rust
  • rust配置
  • seajs
  • session
  • 路由器烧录
  • 烧录
  • 极路由2烧录
  • 砖头烧录
  • 免费服务器
  • 空间
  • 资源
  • 深圳政府电话
  • 深圳电话
  • 特区电话
  • 居住证
  • 居住证签注
  • 深圳新居住证
  • 国庆骑行
  • 深圳珠海骑行
  • 骑行
  • 世界那么大
  • css3
  • css在线生成工具
  • css工具
  • php正则
  • 正则
  • shodan
  • 黑谷歌
  • 黒帽搜素
  • shopex
  • 可视化数据
  • 数据
  • 数据表
  • json
  • json数组
  • json解析
  • socket通信
  • socket多进程
  • socket
  • sql
  • sql优化
  • css3兼容360浏览器兼容模式
  • css圆角
  • 结构体转map
  • config
  • thinkphp
  • 配置文件
  • 树
  • 二叉树
  • js插件
  • web自适应
  • 响应式布局
  • 响应式所有分辨率
  • 自适应布局
  • 自适应所有分辨率
  • mysql设置超时,超时
  • markdown
  • wget
  • wget抓取
  • 网站抓取
  • 我在
  • wordpress
  • wordpress标签
  • 域名合并
  • wpscan
  • usbrip
  • 无限极分类
  • php无限极
  • 分类tree
  • 无限极分类树型
  • xhprof
  • webman
  • laravel
  • composer插件
  • html
  • 响应式分辨率
  • 响应式调试
  • 自适应屏幕
  • 携程
  • 携程攻击
  • 携程网站瘫痪
  • 物理删除
  • 3D
  • 动画
  • 平台
  • 游戏
  • 虚幻4引擎编辑
  • 生成唯一id
  • 生成id
  • 发邮件
  • 邮件函数
  • 储蓄卡免年费
  • 银行卡
  • 银行卡免年费
  • composer安装
  • composer配置
  • 项目创建composer
  • mysql优化
  • mysql读写优化
  • 数据库优化,mysql语句优化
  • php加密
  • php技术
  • 夕阳
  • mysql函数
  • php中mysql函数
  • 互联网时代
  • 开源技术
  • web框架
  • php抓取图片
  • php批量抓取页面图片
  • 邮箱服务器
  • 正则表达式
  • 翻墙
  • 谷歌
  • 谷歌搜索

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 常用命令操作
  • 常用配置
  • 软件仓库
  • swoole
  • webman
  • swoft中文文档
  • Hyperf
  • Easyswoole
  • imi
  • Laravel中文文档
  • MongoDB权限说明
  • gin官方文档
  • Redis性能指标监控
  • Elasticsearch基本CURD
  • mysql性能
  • 故障分析
  • 正则表达式
  • Docker中文文档
  • KubeOperator文档
  • 深入理解PHP内核
  • gRPC中文文档
  • PHP标准规范
  • PHP中文手册
  • agentzh的Nginx教程
  • Nginx第三方模块试用记
  • openresty介绍
  • cors
  • W3C
  • 法律知识
  • 数据结构和算法动态可视化
  • XSS'OR
  • rot13
  • 在线工具
  • 正则表达式验证
  • kali工具
  • 测试工具
  • 安全工具
  • 数据工具
  • 实用工具
  • 监控工具
  • 云海鹰影博客
  • 小兔博客
  • 胡涂说
  • Ric's Blog
  • 介绍:已有十多年开发经验,主要语言PHP、Web、Go、Java、Python等,有涉及R、Rust、Ruby。 最大的收获就是学好一门语言,其他的更好学。
  • 站长:艾瑞可erik
  • 邮箱:erik@erik.xyz