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

  • 相关阅读:
    CodeForces 706C Hard problem
    CodeForces 706A Beru-taxi
    CodeForces 706B Interesting drink
    CodeForces 706E Working routine
    CodeForces 706D Vasiliy's Multiset
    CodeForces 703B Mishka and trip
    CodeForces 703C Chris and Road
    POJ 1835 宇航员
    HDU 4907 Task schedule
    HDU 4911 Inversion
  • 原文地址:https://www.cnblogs.com/lizimeme/p/6825765.html
Copyright © 2011-2022 走看看