• [js高手之路]javascript腾讯面试题学习封装一个简易的异步队列


    这道js的面试题,是这样的,页面上有一个按钮,一个ul,点击按钮的时候,每隔1秒钟向ul的后面追加一个li, 一共追加10个,li的内容从0开始计数( 0, 1, 2, ....9 ),首先我们用闭包封装一个创建li元素的函数.

    1         var create = (function(){
    2             var count = 0;
    3             return function(){
    4                 var oLi = document.createElement( "li" );
    5                 oLi.innerHTML = count++;
    6                 return oLi;
    7             }
    8         })();

    页面上的2个元素:

    <input type="button" value="点我">
    <ul id="box"></ul>
    js代码:
     1 var oBtn = document.querySelector( "input" );
     2 var oBox = document.querySelector( "#box" );
     3 
     4 var create = (function(){
     5     var count = 0;
     6     return function(){
     7         var oLi = document.createElement( "li" );
     8         oLi.innerHTML = count++;
     9         return oLi;
    10     }
    11 })();
    12 
    13 oBtn.onclick = function(){
    14     setTimeout(function(){
    15         oBox.appendChild( create() );
    16         setTimeout( function(){
    17             oBox.appendChild( create() );
    18             setTimeout( function(){
    19                 oBox.appendChild( create() );
    20             }, 1000 );
    21         }, 1000 );
    22     }, 1000 );
    23 }

    点击按钮的时候,用回调函数嵌套方式,这里我加入3个li,就已经快受不了了,这就是javascript著名的回调地狱,那么在这里,我用循环简化一下:

     1 var oBtn = document.querySelector("input");
     2 var oBox = document.querySelector("#box");
     3 var timer = oNode =  null;
     4 var create = (function () {
     5     var count = 0;
     6     return function () {
     7         var oLi = document.createElement("li");
     8         oLi.innerHTML = count++;
     9         return oLi;
    10     }
    11 })();
    12 function add(){
    13     oNode = oBox.appendChild( create() );
    14     if ( oNode.innerHTML < 9 ) {
    15         timer = setTimeout( add, 1000 );
    16     }else {
    17         clearTimeout( timer );
    18     }
    19 }
    20 oBtn.onclick = function () {
    21     add();
    22 }

    恩,确实简化了,但是这种面向过程的方式,耦合性太强,下面呢,我就把这个封装成一个通用队列

    第一步:封装一个队列,包含( 入列,出列),队列的特点(先进先出,如果你不懂这个,需要去补下基本的数据结构与算法内容)

     1 var Queue = function () {
     2     this.list = []
     3 }
     4 Queue.prototype = {
     5     constructor: Queue,
     6     enQueue: function ( fn ) {
     7         this.list.push( fn );
     8         return this;
     9     },
    10     deQueue: function () {
    11         var fn = this.list.shift() || function () {};
    12         fn.apply( this, arguments );
    13     }
    14 }

    我们来使用它:

     1 var oQ = new Queue();
     2 oQ.enQueue( function(){
     3     console.log( 'ghostwu1' );
     4 }).enQueue( function(){
     5     console.log( 'ghostwu2' );
     6 }).enQueue( function(){
     7     console.log( 'ghostwu3' );
     8 }).deQueue();
     9 while( oQ.list.length ){
    10     oQ.deQueue();
    11 }

    第二步、虽然我们现在实现了一个队列,但是,这玩意是同步的,接下来继续改造成异步的:

     1 var oQ = new Queue();
     2 oQ.enQueue( function(){
     3     var _this = this;
     4     console.log( 'ghostwu1' );
     5     setTimeout( function(){ _this.deQueue(); }, 1000 );
     6 }).enQueue( function(){
     7     var _this = this;
     8     console.log( 'ghostwu2' );
     9     setTimeout( function(){ _this.deQueue(); }, 1000 );
    10 }).enQueue( function(){
    11     var _this = this;
    12     console.log( 'ghostwu3' );
    13     setTimeout( function(){ _this.deQueue(); }, 1000 );
    14 }).deQueue();

    第三步、这样就实现了一个异步队列, 这里有个小东西要注意下,把this保存下来,因为定时器的this指向的是window.另外在封装deQueue(出列)函数时,一定要给个空函数,否则出列完了之后,会报错,但是这玩意还是有耦合性,继续改造:

     1 <input type="button" value="点我">
     2 <ul id="box"></ul>
     3 <script>
     4 var Utils = {
     5     isFunction: function (a) {
     6         return Object.prototype.toString.call(a) === '[object Function]';
     7     },
     8     isNumber: function (a) {
     9         return typeof a === 'number';
    10     }
    11 };
    12 var Queue = function () {
    13     this.list = []
    14 }
    15 Queue.prototype = {
    16     constructor: Queue,
    17     enQueue: function (fn) {
    18         this.list.push(fn);
    19         return this;
    20     },
    21     delay: function (time) {
    22         this.list.push(time);
    23         return this;
    24     },
    25     deQueue: function () {
    26         var _this = this;
    27         var cur = this.list.shift() || function () { };
    28         if (Utils.isFunction(cur)) {
    29             cur.apply(_this, arguments);
    30             if (_this.list.length) _this.deQueue();
    31         } else if (Utils.isNumber(cur)) {
    32             setTimeout(function () {
    33                 _this.deQueue();
    34             }, cur);
    35         }
    36     }
    37 }
    38 
    39 var oBtn = document.querySelector("input");
    40 var oBox = document.querySelector("#box");
    41 var create = (function () {
    42     var count = 0;
    43     return function () {
    44         var oLi = document.createElement("li");
    45         oLi.innerHTML = count++;
    46         return oLi;
    47     }
    48 })();
    49 oBtn.onclick = function () {
    50     var oQ = new Queue();
    51     function add() {
    52         for (var i = 0; i < 10; i++) {
    53             oQ.enQueue(function () {
    54                 oBox.appendChild(create());
    55             }).delay(1000);
    56         }
    57     }
    58     add();
    59     oQ.deQueue();
    60 }
    61 </script>

    这样封装之后,我们的异步队列就变得通用一点了,把延时和业务逻辑分开处理

  • 相关阅读:
    请求转发和重定向
    jvm调优(新生代、老年代调优)
    servlet(对servlet的理解、生命周期)
    http的get和post请求方式
    jvm垃圾回收器(串行、吞吐量优先、响应时间优先、G1)
    java后端学习路线总结
    jvm:java中的引用(强引用、软引用、虚引用、弱引用)
    jvm直接内存(分配与回收)
    ssm(增删改查、拦截器、过滤器)
    springmvc:文件的上传与下载
  • 原文地址:https://www.cnblogs.com/ghostwu/p/7496370.html
Copyright © 2020-2023  润新知