• 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...

  • 相关阅读:
    EJB 笔记
    设计模式
    go 笔记
    破解ssl pinning 抓APP的https数据包
    python读取、写入csv文件
    Python中用正则匹配手机号码
    苹果手机安装charles证书
    mysql在表中插入一个字段
    Python递归调用自己的函数
    mysql查询语句
  • 原文地址:https://www.cnblogs.com/chenwenhao/p/9314025.html
Copyright © 2020-2023  润新知