zoukankan      html  css  js  c++  java
  • JavaScript下的setTimeout(fn,0)的作用,涨知识了

    单线程的javascript

    首先我们来看浏览器下的JavaScript:

    浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程。

    • javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。

    • GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

    • 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)

    js是单线程的,浏览器有一个js任务队列,当在触发事件里面嵌套触发事件时,嵌套的这些事件会放在队列里面,等当前任务完成后再激活队列中的任务。解决方案就是使用setTimeout再次调整浏览器的代码任务运行队列。

    看下面这2个对比的例子:

     <div>
           <h3>setTimeout</h3>
           <h4>1、未使用 <code>setTimeout</code></h4>
           <button id="generateInput">生成input</button>
    
            <p id="inpwrapper"></p>
       </div>
    
       <div>
           <h3>setTimeout</h3>
           <h4>2、使用 <code>setTimeout</code></h4>
           <button id="generateInput2">生成input</button>
    
           <p id="inpwrapper2"></p>
       </div>
    
       <div>
    
    
           <h3>3、另一个例子, 没有使用setTimeout()</h3>
           <p>
               <input type="text" id="input" value="aa" /><span id="preview"></span>
           </p>
       </div>
       <div>
    
    
           <h3>4、另一个例子, 使用setTimeout()</h3>
           <p>
               <input type="text" id="input2"  /><span id="preview2"></span>
           </p>
       </div>
    

     

    <script>
    
    
    
         function get(id){
            return document.getElementById(id);
         }
    
          window.onload = function(){
          get("generateInput").onmousedown = function(){
             var input = document.createElement('input');
              input.setAttribute('type',"text");
              input.setAttribute('value',"test1");
             get("inpwrapper").appendChild(input);
              input.focus();
              input.select();
    
          }
    
    
    
            get("generateInput2").onmousedown = function(){
                var input = document.createElement('input');
                input.setAttribute('type',"text");
                input.setAttribute('value',"test1");
                get("inpwrapper2").appendChild(input);
                setTimeout(function(){
                    input.focus();
                    input.select();
                },0);
    
    
            };
    
            get('input').onkeypress = function(){
                get("preview").innerHTML = this.value;
            };
            var domInput =  get('input2');
            domInput.onkeypress = function(event){
                console.log(event);
                setTimeout(function(){
                    console.log();
                    get("preview2").innerHTML = domInput.value;
                },0);
            }
        }
    </script>

    基本效果展示:

    未使用setTimeout(),测试新生成的input的focus事件是被丢弃了还是被触发了,加强版测试例子1:

       function get(id){
            return document.getElementById(id);
         }
    
          window.onload = function(){
              var gener1 =   get("generateInput");
              gener1.onmousedown = function(e){
                  console.log(e.type);
             var input = document.createElement('input');
              input.setAttribute('type',"text");
              input.setAttribute('value',"test1");
             get("inpwrapper").appendChild(input);
              input.onfocus = function(){
                  console.info('input focus');
              };
              input.focus();
              input.select();
    
          };
              gener1.onclick =function(e){
                  console.log(e.type);
              };
              gener1.onmouseup =function(e){
                  console.log(e.type);
              };
              gener1.onfocus =function(e){
                  console.log("gener1 focus");
              };
    

      结果如下:

      例子1中,我们点击的按钮,在mousedown之后,才获得焦点,也就是说:我们的input本来已经得到了focus(),但在onmousedown之后,我们点击的按钮才迟迟触发了自己的onfocus(),导致我们的input的focus被覆盖。所以input才没有获得焦点。

    未使用setTimeout(fn,0)之前,任务流程是这样的:

    onmousedown->onmousedown中执行了input.focus=>button.onfoucs=>onmouseup=>onclick

    使用setTimeout()后测试新生成的input的focus事件是被丢弃了还是被触发了,加强版测试例子1:

     var gener2 = get("generateInput2");
               gener2.onmousedown = function(e){
                   console.log(e.type);
                var input = document.createElement('input');
                input.setAttribute('type',"text");
                input.setAttribute('value',"test1");
                get("inpwrapper2").appendChild(input);
                   input.onfocus = function(){
                       console.info('input focus');
                   };
                setTimeout(function(){
                    input.focus();
                    input.select();
                },0);
    
    
              };
              gener2.onclick =function(e){
                  console.log(e.type);
              };
              gener2.onmouseup =function(e){
                  console.log(e.type);
              };
              gener2.onfocus =function(e){
                  console.log("gener1 focus");
              };
    

      运行结果如下:

    示例2中的代码,我们延迟了焦点,当按钮获得焦点之后,我们的input再把焦点抢过来,所以,使用setTimeout(fn,0)之后,我们的input可以得到焦点并选中文本。

     使用了setTimeout之后任务流程是这样的:

    onmouseup->button.onfocus=>input.focus=>onmouseup=>onclick

    在工作学习中,我看到团队中的有些大神的代码中不时的出现setTimeout(fn,0);这样的写法,很好奇,这样写的作用是什么,在网上,经过一位网友无私耐心地阐述,我才对js单线程的机制有了更深的认识,此处我引上链接,与君共勉!

    http://www.cnblogs.com/silin6/p/4333999.html

  • 相关阅读:
    Redis 优缺点
    如何保证接口的幂等性。。。。。
    自动化部署 jenkins 插件简介
    JWT与Session比较和作用
    代码注释鉴赏,喜欢就拿去用!
    python中计时模块timeit的使用方法
    【Java】JavaIO(二)、节点流
    【Java】JavaIO(一)、基础知识
    【Git】四、Git工作
    【Git】三、工作区、暂存区、版本库
  • 原文地址:https://www.cnblogs.com/lizimeme/p/6825765.html
Copyright © 2011-2022 走看看