【问题标题】:How do I store javascript functions in a queue for them to be executed eventually [duplicate]如何将javascript函数存储在队列中以便最终执行[重复]
【发布时间】:2010-10-28 07:10:28
【问题描述】:

我在 javascript 中创建了一个 Queue 类,我想将函数作为数据存储在队列中。这样我就可以构建请求(函数调用)并在需要时响应它们(实际执行函数)。

有没有办法将函数存储为数据,有点类似于

.setTimeout("doSomething()", 1000);

除非是

functionQueue.enqueue(doSomething());

它将 doSomething() 存储为数据的位置,因此当我从队列中检索数据时,将执行该函数。

我猜我必须在引号中加上 doSomething() -> "doSomething()" 以及如何让它使用字符串调用函数,有人知道怎么做吗?

【问题讨论】:

    标签: javascript function timeout queue


    【解决方案1】:

    所有函数实际上都是变量,因此将所有函数存储在数组中实际上非常容易(通过在没有() 的情况下引用它们):

    // Create your functions, in a variety of manners...
    // (The second method is preferable, but I show the first for reference.)
    function fun1() { alert("Message 1"); };
    var fun2 = function() { alert("Message 2"); };
    
    // Create an array and append your functions to them
    var funqueue = [];
    funqueue.push(fun1);
    funqueue.push(fun2);
    
    // Remove and execute the first function on the queue
    (funqueue.shift())();
    

    如果您想将参数传递给您的函数,这会变得有点复杂,但是一旦您设置了执行此操作的框架,之后每次都变得容易。本质上,您要做的是创建一个包装函数,该函数在被调用时会触发具有特定上下文和参数集的预定义函数:

    // Function wrapping code.
    // fn - reference to function.
    // context - what you want "this" to be.
    // params - array of parameters to pass to function.
    var wrapFunction = function(fn, context, params) {
        return function() {
            fn.apply(context, params);
        };
    }
    

    现在我们已经有了一个用于包装的实用函数,让我们看看它是如何用于创建未来的函数调用的:

    // Create my function to be wrapped
    var sayStuff = function(str) {
        alert(str);
    }
    
    // Wrap the function.  Make sure that the params are an array.
    var fun1 = wrapFunction(sayStuff, this, ["Hello, world!"]);
    var fun2 = wrapFunction(sayStuff, this, ["Goodbye, cruel world!"]);
    
    // Create an array and append your functions to them
    var funqueue = [];
    funqueue.push(fun1);
    funqueue.push(fun2);
    
    // Remove and execute all items in the array
    while (funqueue.length > 0) {
        (funqueue.shift())();   
    }
    

    可以通过允许包装器使用数组或一系列参数来改进此代码(但这样做会混淆我正在尝试制作的示例)。

    【讨论】:

    • 我自己做了很多,但从没想过同时存储上下文和参数。非常好。
    • 它如何工作宽度异步方法,如 ajax 请求,我如何链接 ajax 方法?
    • 函数不是变量而是对象。不过非常有帮助的帖子!谢谢!
    • 谢谢,一旦页面顶部的元素滚动到视口上方,我一直在努力平滑删除它们。 iOS 8 让这变得很困难,而您的速度检测节省了一天的时间!
    • 如果你想从内部函数中捕获返回的结果,请使用:return fn.apply(context, params);
    【解决方案2】:

    发布的规范答案here


    这是一个不错的 Queue 类,您可以在不使用超时的情况下使用:

    var Queue = (function(){
    
        function Queue() {};
    
        Queue.prototype.running = false;
    
        Queue.prototype.queue = [];
    
        Queue.prototype.add_function = function(callback) { 
            var _this = this;
            //add callback to the queue
            this.queue.push(function(){
                var finished = callback();
                if(typeof finished === "undefined" || finished) {
                   //  if callback returns `false`, then you have to 
                   //  call `next` somewhere in the callback
                   _this.next();
                }
            });
    
            if(!this.running) {
                // if nothing is running, then start the engines!
                this.next();
            }
           
            return this; // for chaining fun!
        }
    
        Queue.prototype.next = function(){
            this.running = false;
            //get the first element off the queue
            var shift = this.queue.shift(); 
            if(shift) { 
                this.running = true;
                shift(); 
            }
        }
    
        return Queue;
    
    })();
    

    可以这样使用:

    var queue = new Queue;
    queue.add_function(function(){
       //start running something
    });
    queue.add_function(function(){
       //start running something 2
    });
    queue.add_function(function(){
       //start running something 3
    });
    

    【讨论】:

    • 在许多情况下使用不使用 setTimeout 是可以的。拥有一个 setTimeout 当然(在这里提到这一点)有助于将执行返回给 Javascript task queue/event loop。这样冗长的代码部分不会阻塞浏览器。
    【解决方案3】:

    请参阅您存储的函数,末尾没有 ()。 doSomething 是一个变量(恰好是一个函数); doSomething() 是执行函数的指令。

    稍后,当您使用队列时,您会想要(functionQueue.pop())() 之类的东西——即执行functionQueue.pop,然后执行pop 调用的返回值。

    【讨论】:

      【解决方案4】:

      你也可以使用函数对象的.call()方法。

      function doSomething() {
          alert('doSomething');
      }
      
      var funcs = new Array();
      
      funcs['doSomething'] = doSomething;
      
      funcs['doSomething'].call();
      

      另外,你也可以直接将函数添加到队列中:

      funcs['somethingElse'] = function() {
          alert('somethingElse');
      };
      
      funcs['somethingElse'].call();
      

      【讨论】:

        猜你喜欢
        • 2019-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-30
        相关资源
        最近更新 更多