日期:2014-05-16  浏览次数:20353 次

[转]只有7行代码的异步调用 js 库

7 lines JavaScript library for calling asynchronous functions

I was surprised by the good feedback for JavaScript template engine in just 20 lines and decided to blog for another small utility function which I'm using often. While we are talking about JavaScript in the browser, most of the operations are asynchronous. We are dealing with callbacks all the time and sometimes we end up with awesome callback hell.

?

Let's say that we have two functions and we want to call them one after each other. They both operate with same variable. The first one sets its value and the second one uses it.

?

    var value;
    var A =function(){
          setTimeout(function(){
               value =10;
          },200);
    };

    var B =function(){
        console.log(value);
    };

    调用方法:
     A();
     B();
     执行结果: undefined
?

So, if we now run A();B(); we will get undefined in the console. It's like that because the A function sets the value asynchronously. What we could do is to send a callback and execute it once the job is done.

?

    var value;
    var A =function(callback){
          setTimeout(function(){
                value =10;
                callback();
          },200);
    };

    var B =function(){
           console.log(value);
    };
     
    A(function(){
         B();
    });
    执行结果: 10

?

This works, but imagine what will happen if we need to run five or more methods. Passing callbacks all the time will lead to messy and unpleasant code.

?

The idea is to write a helper function which accept our workers and handle the whole process. Let's start with the simplest thing:

?

    var queue =function(funcs){
          // magic here
    }
?

So, what we have to do is to run that function by passing the both A and B - queue([A, B]). We need to get the first function and execute it.

?

    var queue =function(funcs){
         var f = funcs.shift();
         f();
    }
?

If you run this code you will see an error TypeError: undefined is not a function. That's because A function doesn't accept callback but it tries to run it. Let's pass one.

?

    var queue =function(funcs){
           varnext=function(){
               // ...
           };
          var f = funcs.shift();
          f(next);
    };
?

The next method is getting called once A finishes its job. That's the perfect place for continuing to the next function in the list. We could arrange the code a bit and we are able to go through the whole array.

?

    var queue =function(funcs){
           varnext=function(){
                var f = funcs.shift();
                f(next);
           };
           next();
    };
?

If we leave the things like that we will reach our goal. I.e. function A is called and just after that B, which prints the correct value of the variable. The key moment here is the usage of shift method. It removes the first element of the array and returns the element. Step by step funcs array becomes empty. So, this could lead to an error. To prove this theory, let's assume that we still need to run the both functions, but we don't know their order. In this case, they both should accept callback and execute it.

    var A =function(callback){
          setTimeout(function(){
               value =10;