开发者

Enabling chained method using ".delay"

开发者 https://www.devze.com 2023-01-10 07:17 出处:网络
I\'d like to know how to realize this method-chain style: var foo = function(){}; foo.prototype = { say : function(s){

I'd like to know how to realize this method-chain style:

var foo = function(){};

foo.prototype = {
 say : function(s){
        alert(s);
        return this;
       },
 delay : function(ms){
          var _this = this;
          setTimeout(function(){
           return _this;
          }, ms);
         return this; // If I omit this, there will be an erro开发者_运维知识库r.
         }
}

var bar = new foo();
bar.delay(2000).say('hello'); // this will immediately alert 'hello'.

I want to use like this:

bar.delay(2000).say('hello'); // in 2 sec. say 'hello'.

not like this:

bar.delay(2000, function()...); // it's not a chained method

Is it possible ?


Yes it's possible but you can't do it by simply returning from the delay() function after ms - calls to setTimeout are asynchronous and so return immediately. To achieve this effect you must implement your own queuing system. Some code:

var queue = new Queue();

function delay(ms) {
    queue.enqueue("delay");
    setTimeout(function() {
        popQueue(true);
    }, ms);

    return this;
}

function say(s) {
    queue.enqueue(function() {
        alert(s);
    });
    popQueue();

    return this;
}

function popQueue(removeDelay) {
    if (removeDelay) {
        if (queue.peek() == "delay") queue.dequeue();
    }
    while (!queue.isEmpty() && queue.peek() != "delay") {
        (queue.dequeue())();
    }
}

In essence, the code works by modifying every function that is "delayable", so that it inserts itself into a queue, rather than executing immediately. The delay() function inserts a string into the queue as a "blocking" item, that prevents functions added to the queue from executing. You can then use a timeout to remove the block from the queue after the given number of milliseconds.

The above code just gives you an idea of how delaying can be implemented but isn't a working example. Obviously you'd need some sort of Queue implementation, or you can modify it to use arrays, or you can implement your own SelfExecutingQueue object to automatically continue to execute functions (until it hits a non-function object) immediately after queuing or dequeuing without requiring you to manually call popQueue(), etc...


Thanks to advice, I made it! Here is the code.

var foo = function(){};

foo.prototype = {
 say : function(s){
  Queue.enqueue(function(){
   alert(s);
  });
  Queue.flush();
  return this;
 },
 delay : function(ms){
  Queue.enqueue('delay:' + ms);
  return this;
 }
}

Queue = {
 entries : [],
 inprocess : null,
 enqueue : function(entry){
  Queue.entries.push(entry);
 },
 flush : function(){
  if(Queue.inprocess) return;
  while (Queue.entries.length){
   var entry = Queue.entries.shift();
   if(entry.toString().indexOf('delay:') !== -1){
    var ms = Number(entry.split(':')[1]);
    Queue.inprocess = setTimeout(function(){
     Queue.inprocess = null;
     Queue.flush();
    }, ms);
    return;
   }
   entry();
  }
 }
}

I prepared a Queue object to manage functions' entries. With this, I can play with a method-chain:

var bar = new foo();
bar.delay(2000).say('Hello, ').delay(3000).say('world!');

Many thanks!

0

精彩评论

暂无评论...
验证码 换一张
取 消