JS异步执行之setTimeout 0的妙用
最近在工作中遇到一些问题,大致是关于js执行问题的。由于没搞清执行顺序,导致出现了一些奇怪的bug。 所以这里整理一些有关异步执行的知识(冰山一角角)...
大家都知道js是单线程的,执行起来是顺序的,在顺序的业务逻辑中当然没有问题。如果遇到可以并发执行的业务逻辑,再排队就很低级了,所以需要异步执行!
1、什么是异步?
setTimeout(function(){
console.log(0);
},0)
console.log(1);
// 先打印 1
// 再打印 0
比方说有些饭店你去吃饭需要提前预定(异步代码执行),等其他人吃完(同步代码执行完毕)你才能去,因此在其他人吃饭的时候(同步代码执行中)你可以去干其他的事情,等其他人吃完了(同步代码执行完毕)会有人来通知你,于是你可以去了(开始执行异步代码【setTimeout/setInterval/事件处理程序/ajax回调...】的执行)。
我们回到前面那段setTimeout身上,它的工作原理是这样的,当你定义setTimeout那一刻起(不管时间是不是0),js并不会直接去执行这段代码,而是把它扔到一个事件队列里面,当页面中所有同步任务都干完了以后,才会去执行事件队列里面的代码。什么是同步,按代码顺序执行,就像音乐播放器里的顺序播放。
2、setTimeout 0的妙用
<!DOCTYPE html>
<html>
<head>
<title> </title>
<meta charset="utf-8">
</head>
<body>
<p>
<input type="text" id="input" value=""/>
<span id="preview"></span>
</p>
</body>
<script type="text/javascript">
(function(){
function $(id){
return document.getElementById(id);
}
$('input').onkeypress = function(){
$('preview').innerHTML = this.value;
}
})();
</script>
</html>
这个keypress函数原意是监听到用户输入字符串就将其完整的显示出来,但是奇怪的是最后一个字符串总是没能显示出来:

重点来了,使用setTimeout 0来解决:
$('input').onkeypress = function(){
setTimeout(function(){ $('preview').innerHTML = $('input').value;},0);
}
好的,问题就这样解决了,首先回过头来看看问题是如何产生的?
代码中,我们用到的事件是keypress,而keypress事件发生时,dom元素的状态还未改变,keypress事件之后dom元素的状态才发生改变,通过setTimeout 0延迟执行就能达到期望的结果了。当然,不用setTImeout 0 ,直接用onkeyup亦可。
但是setTimeout有些小小的问题,就是时间不精确:
<!DOCTYPE html>
<html>
<head>
<meta name="generator" content="">
<title></title>
<meta charset="utf-8">
</head>
<body>
<h2>未使用 <code>setTimeout</code></h2>
<button id="makeinput">生成 input</button>
<p id="inpwrapper"></p>
</body>
<script type="text/javascript">
(function(){ function get(id){
return document.getElementById(id);
}
function log(a){
console.log(a)
} window.onload = function(){
get('makeinput').onmousedown=function(){
var input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('value', 'test1');
get('inpwrapper').appendChild(input);
input.onfocus=function(){ //给生成的input绑定focus事件
log("iptFocus");
}
input.focus();
log("down");
}
get('makeinput').onfocus = function(){
log("btnFocus");
}
get('makeinput').onclick = function(){
log("click");
}
get('makeinput').onmouseup=function(){
log("up");
}
}
})();
</script>
</html>
// 打印 iptFocus
// 打印 down
// 打印 btnFocus 导致新增的input无焦点的真凶
// 打印 up
// 打印 click
将 input.focus(); 改为 setTimeout(function(){input.focus();},0);得到结果为:
// 打印 down
// 打印 btnFocus
// 打印 iptFocus 鬼知道为什么会跑到这执行
// 打印 up
// 打印 click
理解了js的异步执行和setTImeout 0的工作原理,能更好的方便我们解决工作中的bug...
JS异步执行之setTimeout 0的妙用的更多相关文章
- 浅析JS异步执行机制
前言 JS异步执行机制具有非常重要的地位,尤其体现在回调函数和事件等方面.本文将针对JS异步执行机制进行一个简单的分析. 从一份代码讲起 下面是两个经典的JS定时执行函数,这两个函数的区别相信对JS有 ...
- js 异步执行顺序
参考文章: js 异步执行顺序 1.js的执行顺序,先同步后异步 2.异步中任务队列的执行顺序: 先微任务microtask队列,再宏任务macrotask队列 3.调用Promise 中的res ...
- js异步执行 按需加载 三种方式
js异步执行 按需加载 三种方式 第一种:函数引用 将所需加载方法放在匿名函数中传入 //第一种 函数引用 function loadScript(url,callback){ //创建一个js va ...
- js异步执行原理
我们都知道js是一个单线程的语言,所以没办法同时执行俩个进程.所以我们就会用到异步. 异步的形式有哪些那,es5的回调函数.es6的promis等 异步的运行原理我们可以先看下面这段代码 应该很多人都 ...
- 从一到面试题了解js异步机制:setTimeout 和 Pronmise
1.毫无疑问setTimeout是最晚输出的 2.请无视undefined,这是浏览器的返回值. 3.new Promise中并不是异步,而.then()后才是异步.
- 异步执行js脚本——防止阻塞
JS允许我们修改页面中的所有方面:内容,样式和用户进行交互时的行为. 但是js同样可以阻塞DOM树的形成并且延迟页面的渲染. 让你的js变成异步执行,并且减少不必要的js文件从而提高性能. JavaS ...
- 【JS】js引擎执行过程
概述 js引擎执行过程主要分为三个阶段,分别是语法分析,预编译和执行阶段,上篇文章我们介绍了语法分析和预编译阶段,那么我们先做个简单概括,如下: 语法分析: 分别对加载完成的代码块进行语法检验,语法正 ...
- js异步队列之理解
起因 最近看到一篇关于js异步执行顺序的解答,觉得有所收获,遂记录下来. marcotask和microtask js中异步队列可以分为两类,marcotask队列和microtask队列, marc ...
- js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)
javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...
随机推荐
- MongoDB 副本集配置,开启账号认证
MongoDB 自带功能强大的主从,配置也很简单,从零开始花了30分钟搞定 3台以上机器IP: 192.168.1.24, 192.168.1.25, 192.168.1.26, 192.168.1. ...
- C语言数据结构-链式队列的实现-初始化、销毁、清空、长度、队列头元素、插入、删除、显示操作
1.数据结构-链式队列的实现-C语言 typedef struct QNode { int data; struct QNode *next; }QNode,*QueuePtr; typedef st ...
- 公共子序列(luogu P1439)
传送门 题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出格式: 一个数,即最 ...
- c语言数据结构学习心得——树
树 一对多的树型结构,有且只有一个特定的根结点. 结点的度:结点拥有子树的数量{ 度为0:叶子结点/终端结点. 度不为0:非终端结点/分支结点(除去根结点其它称为内部结点).} 树的度:树中所有结点的 ...
- 使用vue-cli脚手架搭建项目,保存编译时出现的代码检查错误(ESLint)
一.问题 出现这么写错误是什么原因呢?相信很多小白都会像我一样,第一次接触时有点二丈和尚摸不着头脑.其实是在你用vue-cli脚手架构建项目时用了ESLint代码检查工具,如下图 那么什么是ESLin ...
- qt线程睡眠
头文件 #include <QThread> 接口函数: void QThread::sleep ( unsigned long secs ) [static protected] v ...
- promise的一个简单易懂实例
Promise: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- Springboot 整合 中国移动MAS HTTP1.0 实现短信发送服务(二)
原因:身份验证传入的参数包含中文企业名,因为本地编码格式是支持中文的:而客户的服务器中文却乱码,导致传给中国移动MAS服务器的是乱码的信息. 解决:非常简单,将中文信息转为UTF-8.例如(%E5%8 ...
- C++_代码重用2-包含对象成员的类
对于姓名可以使用字符数组来表示,但这将限制姓名的长度.当然,还可以使用char指针和动态内存分配,但这要求提供大量的支持代码.有一个好的方法就是使用一个他人开发好的类的对象来表示.如果C++库提供了合 ...
- spark SQL编程
1.编程实现将 RDD 转换为 DataFrame源文件内容如下(包含 id,name,age): 1,Ella,362,Bob,293,Jack,29 请将数据复制保存到 Linux 系统中,命名为 ...