Simple but difficult. How to force external libs functions run sequentially?

88 views Asked by At

If we have two function in javascript, one slow and one fast. For example:

function slow() {
    setTimeout(function() {console.log("slow finished")}, 10000);
}

function fast() {
    console.log("fast");
}

And these functions don't have inside of them new structures like promisses (if we do not implement after).

How can we force these functions run in order? For example:

function run() {
    slow();
    fast();
}

run();

How can we force fast wait slow finishes? I'm looking a solution that could work inside mobile application browsers, becase of a Apache Cordova project of mine.

Is there a way to do this?

An idea of mine is inject a callback function between the functions. And this callback is called at the end of the slow function, calling the fast function.

An important thing is I can't (or would not) rewrite the code of the slow and fast functions, because they will reside inside external libraries.

I'm looking for a solution to countorn this problem as an external observer and manager.

How can we do this?

Edit

He I was a trying to solve the problem merging the answers. No success yet. I had changed slow but this is not really allowed. I have changed it to se what is happening with a. I couldn't get something interesting because a becomes undefined immediately and not after slow finishes...

  var a = "adsfadsfadsf";
  function slow() {
    setTimeout(function() {console.log("slow done"); console.log("a2", window.a);}, 3000);
  }

  function fast() {
    console.log("a3", window.a);
    console.log("fast done");
  }

  var newSlow = function() {
    return new Promise(function(resolve, reject){
      window.a = slow();
      console.log("a", a);
      resolve("Sucess");
    });
  };

  newSlow().then(function(resolve){fast();}, function(reject){console.log("error");});

I have tried with resolve(slow()); no sucess too.

2

There are 2 answers

4
Saumil On

That's a very interesting question. Well I can think of a way where if it is changing some global variable "g" to some value say "true". In that case if you can run them sequentially as,

<script>
var g = false;
var i;
function slow() {
setTimeout(function() {console.log("slow finished");g=true;}, 10000);
}

function fast() {
    console.log("fast");
}
    function run() {
    slow();
    i = setInterval(function(){check();},1000);
}
function check(){

    if(g){
        fast();
        clearInterval(i);
    }    
}
run();
</script> 

As in this demo

UPDATE: Something just struck me and I guess we might be able to add a callback function to slow() even if we can't access it directly.

If a function is called without parenthesis then the entire function as a content is returned as a string so we can edit that string by adding fast() to it registering that string as a function using eval().

function run() {
    var myFun = slow+"";
    myFun = myFun.substring(0,myFun.length-1);
    alert(myFun);
    myFun += "fast();}";

    //to register the string "myFun" as a function
    eval(myFun);

    slow();
}

So basically our slow() function becomes,

function slow(){

    //function code

    //the appended function
    fast();

}

NOTE: This will not worked in the example given above where GarouDan has deliberately added setTimeout limit to recreate a scenario where the slow() function takes longer time than the fast() function. However, in a real-world scenario I'm sure this approach would definetly work.

1
Gojira On

You could use the Promise pattern.

Promises are tailor made for situations where various parts of code may run slow or fast or complete in unknowable amounts of time (or not complete at all), while still giving you execution control.

My personal favorite library that implements the Promise pattern is RSVP.

Here is some pseudocode to give you the idea. Run an operation that may take a long time, then run one only when the first has either completed, or handle it's failure.

function doFoo() {

    var promise = new RSVP.Promise(function(resolve, reject) {

    // do some long-running operation, like retrieve
    // data from a slow site...

    if (data.Status && data.Status === 200) {
        resolve(data);
    } else {
        reject(data.Error)
        }

    });
    return promise;
}

function doBar() {
    var promise = new RSVP.Promise(function(resolve, reject) {

        // do some fast operation, like count to 10
        for (i = 0; i < 10; i++) {
            console.log(i);
        }

        resolve("");
    });
    return promise;
}

Now you can call:

function inOrder() {
    doFoo().then(function(success) {
        doBar();
    }).catch (function(failure) {
        console.log("oops! " + failure);
    }
    });
}

This runs doFoo, and ONLY runs doBar after doFoo has completed successfully. Note that you could also run doBar even if doFoo has failed.