JS魔法堂:初探传说中的setImmediate函数
一、前言
由于JavaScript程序为单线程,因此在执行长时间的操作时(如循环和递归操作)到导致UI线程长期被阻塞,无法响应用户操作请求(如点击按钮等),让用户体验大打折扣。于是想到将一个长时间操作切片成N个小操作并异步执行,例如jsDeferred中的 Deferred.repeat函数
就提供这样的解决办法,其实质就是通过 setTimeout事件
或 script元素
的 onerror/onload事件
来异步调用这些小操作,从而尽早释放UI线程。
从IE10开始引入了setImmediate接口来代替setTimeout来完成上述功能,下面将记录该接口的资讯,由于内容会涉及到event loop、调用栈等知识,而我对相关内容了解仍不全面,因此下面的内容若有纰漏请各位指正,谢谢!
二、同步和异步调用
由于JavaScript是通过异步调用来尽早释放UI线程,因此我们先要了解同步和异步执行的具体含义:
任务的执行实质上分为两步:①.执行,②.获取执行结果。
同步执行:执行后等待直到获取执行结果;
异步执行:执行后不等待,而是通过一系列手段(轮询、事件监听和event loop等)获取执行结果,而在执行后和获取结果前的那段时间可以介入其他任务操作。
二、setTimeout(handler, 0)的问题
由于setTimeout存在时间精度,因此setTimeout(handler,0)中setTimeout事件插入事件队列的延时必定大于0ms,而handler的执行延时则更大了。具体为IE5~8和不插电源的IE9的时间精度为15.6ms,插电源的IE9和其他浏览器则为4ms。
经微软和Chrome团队实验所得降低时间精度将会大大缩短笔记本的续航时间,也是就说更耗电,因此即使浏览器厂商有能力缩短时间精度,但基于多方面的考虑,依然保持上述的精度值。
三、setImmediate接口
对于通过异步执行的手段对任务切片,由于UI线程得到释放从而提高用户体验,但相对于采用同步执行,整体的任务执行时间较被拉长,因此我们希望切片的小操作越快执行越好。而setImmediate接口则是为此而生的。
setImmediate(handler)
并不像 setTimeout(handler, 0)
由event loop检测系统时间是否到点然后向事件队列插入一个事件,然后调用事件的回调方法handler。而是监控UI线程的调用栈,一旦调用栈为空则将handler压栈。
理论上通过setImmediate执行异步调用的延时一定比通过setTimeout的短,但事实又是如何呢?
我在IE11上操作测试,setTimout的延时为4ms左右,而setImmediate的延时为2ms左右。
注意:
1. 通过setImmediate的异步调用的延时不是0ms哦!
2. 而且有时候setImmediate的延时比setTimeout的多1~2ms哦!
3. 而且setImmediate和setTimeout的延时均比img元素onerror事件的延时长哦!
推测:
1. 对于setImmediate的延时有时比setTimeout的要长,由于setImmediate要先监控调用栈,若调用栈为空才压栈,那么在压栈之前event loop已经将setTimeout事件的回调函数压栈了。
2. 对于两者均比img元素onerror事件的长,由于设置img.src后马上发起请求(不一定为网络IO)当加载失败时onerror事件则会比setTimeout事件先加入事件队列。
四、总结
本文内容纰漏之处请各位指正,谢谢!
五、参考
http://developer.51cto.com/art/201109/292720.htm
http://msdn.microsoft.com/library/ie/hh920766.aspx
https://github.com/yuzujs/setimmediate
http://www.nczonline.net/blog/2011/09/19/script-yielding-with-setimmediate/
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 2020-07-22-腾讯云-slb-kubeadm高可用集群搭建
- 2020-07-23-kubernetes集群使用腾讯云cbs块存储
- 十一、详解面向对象
- 十二、面向对象实战之封装拖拽对象
- 数组reduce方法的高级用法
- 十七、详解 ES6 Modules
- 超干货!为了让你彻底弄懂 MySQL 事务日志,我通宵肝出了这份图解!
- 什么情况下不能使用最坏情况评估算法的复杂度?
- Python运算符
- kubeadm高可用集群意外删除一mater节点,重新加入失败
- Chevereto——简介及安装
- Typecho开启伪静态并隐藏index.php
- Prism代码高亮Pjax重载函数
- Qt示例-AnalogClock-自定义窗体-使用QPainter的转换和缩放特性简化绘图
- 2019-12-27-traefik