2

I'm trying to add a sleep method in a object, which can be called in the middle of a method chain. I considered to use the setTimeout(), but the javascript thread could not be blocked, and it can not output the correct order I want.

<div id="test"></div>

 function hello(str){
  var text = document.getElementById("text");
  this.eat = function(kind){
    text.innerHTML += "<p>Eat "+ kind + "</p>";
    return this;
  }
  this.sleep = function(delay){
    setTimeout(function(){
      text.innerHTML += "<p>Sleep "+delay + "</p>";
    }, delay);
    return this;
  }
  text.innerHTML += "<p>Hello, "+ str + "</p>";
  return this;
}
var test = hello("guy").sleep(3000).eat("dinner"); 
/* I want an output as: 
      Hello, guy -> (wait 3 secs) Sleep 3000 -> Eat dinner
   But actually the output is:
      Hello, guy -> Eat dinner -> (wait 3 secs) Sleep 3000    
*/  

Does anyone have any ideas on it? Shoud I use the prototype, or some other ways to deal with it? What's more, if I want to add another method, named sleepFirst in this object. When I call it like this:

var test2 = hello("boys").sleepFirst(2000).eat("lanch")

it outputs:
(wait 2 secs) sleepFirst 2000 -> Hello, boys -> Eat lanch

What should I do?
(Postscript: I am a beginner in Web Development, maybe someone has asked a similar question before but I had searched for a long time and can't find it out T^T I am a Chinese guy and sorry that my English may seem not so good. Thanks ~~)

ArK
  • 20,698
  • 67
  • 109
  • 136
  • 4
    Interesting question. JS is asynchronous, so one way to go about it would be to add a callback to your sleep method, although that wouldn't be a chain then. Another way would be a queue system http://stackoverflow.com/questions/14365318/delay-to-next-function-in-method-chain – rdiz Apr 10 '15 at 10:24
  • @ArK Oh Yes! The way of queue is workable! – little_tao_ Apr 10 '15 at 11:44

1 Answers1

0

@RobG convinced me to rewrite your piece of code using a real object definition. JsFiddle here.

var sleeper = {
    text: document.getElementById("text"),
    eat: function (kind) {
        text.innerHTML += "<p>Eat " + kind + "</p>";
        return this;
    },
    sleep: function (delay, func, param) {
        setTimeout(function () {
            func(param);
            //text.innerHTML += "<p>Sleep " + delay + "</p>";
        }, delay);
        return this;
    },
    hello: function (str) {
        text.innerHTML += "<p>Hello, " + str + "</p>";
        return this;
    }
};

sleeper.hello("guy").sleep(3000, sleeper.eat, "dinner");

It's way much better. But this way you won't be abble to perform a chain of more than one call.

Amessihel
  • 5,891
  • 3
  • 16
  • 40
  • 1
    Note that *this* references the global object, likely that isn't what you're expecting, `this.sleep = ...;` is creating a global property, and you keep returning *this*, which is the global object, so your code is equivalent to `hello('guy'); sleep(...);`. Try it. – RobG Apr 10 '15 at 10:48
  • [edited cause you edited your answers.] You're right, I just modified this code to make it _working_, not _efficient_. – Amessihel Apr 10 '15 at 10:52
  • @Amessihel Thank you! Also I've been suggested that I can use a queue to deal with that, and I find it is a workable way [link](http://stackoverflow.com/questions/14365318/delay-to-next-function-in-method-chain) – little_tao_ Apr 10 '15 at 12:04
  • Yep I saw it ! You can also buid a function this way : `function sleepyRun(delay1, call1, delay2, call2, ...)` You can manage functions with unlimited arguments. See [https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Fonctions/arguments](this) if you want to check out this way. – Amessihel Apr 10 '15 at 12:41