Spiga

支持链式调用的异步调用框架Async.Operation

2009-06-30 18:05 by Cat Chen, 147 visits, 网摘, 收藏, 编辑
Async = {};

Async.Operation 
= function(options) {
    options 
= options || {};

    
var callbackQueue = [];
    
var chain = (options.chain && options.chain === true? true : false;
    
var started = false;
    
var innerChain = null;
    
    
this.result = undefined;
    
this.state = "running";
    
this.completed = false;
    
    
this.yield = function(result) {
        
var self = this;
        
        
if (!chain) {
            self.result 
= result;
            self.state 
= "completed";
            self.completed 
= true;
        }
 else {
            started 
= true;
            self.result 
= result;
            self.state 
= "chain running";
            self.completed 
= false;
        }


        setTimeout(
function() {
            
if (!innerChain) {
                
while (callbackQueue.length > 0{
                    
var callback = callbackQueue.shift();
                    
if (chain) {
                        callbackResult 
= callback(self.result);
                        self.result 
= callbackResult;
                        
if (callbackResult && callbackResult instanceof Async.Operation) {
                            innerChain 
= Async.chain();
                            
while (callbackQueue.length > 0{
                                innerChain.next(callbackQueue.shift());
                            }

                            innerChain.next(
function(result) {
                                self.result 
= result;
                                self.state 
= "completed";
                                self.completed 
= true;
                                
return result;
                            }
);
                            callbackResult.addCallback(
function(result) {
                                self.result 
= result;
                                innerChain.go(result);
                            }
);
                        }

                    }
 else {
                        callback(self.result);
                    }

                }


                
if (!innerChain) {
                    self.state 
= "completed";
                    self.completed 
= true;
                }

            }
 else {
                
while (callbackQueue.length > 0{
                    innerChain.next(callbackQueue.shift());
                }

                innerChain.next(
function(result) {
                    self.result 
= result;
                    self.state 
= "completed";
                    self.completed 
= true;
                    
return result;
                }
);
            }

        }
1);
        
return this;
    }
;

    
this.go = function(initialArgument) {
        
return this.yield(initialArgument);
    }


    
this.addCallback = function(callback) {
        callbackQueue.push(callback);
        
if (this.completed || (chain && started)) {
            
this.yield(this.result);
        }

        
return this;
    }
;

    
this.next = function(nextFunction) {
        
return this.addCallback(nextFunction);
    }
;
}
;

Async.chain 
= function(firstFunction) {
    
var chain = new Async.Operation({ chain: true });
    
if (firstFunction) {
        chain.next(firstFunction);
    }

    
return chain;
}
;

Async.go 
= function(initialArgument) {
    
return Async.chain().go(initialArgument);
}
0
0
(请您对文章做出评价)
« 上一篇:拆分自然数:纯while实现 (Part 2 - 实现)
» 下一篇:写个 JavaScript 异步调用框架 (Part 5 - 链式实现)
Add your comment

10 条回复

  1. #1楼 普通男孩      2009-10-19 16:21
    你好,我是一个js菜鸟.我是这么调用的...
    ...
    var chain = Async.go(0);
    chain
    .next(function(){setTimeout("alert(1)",3000)})
    .next(function(){setTimeout("alert(2)",3000)})
    .next(function(){setTimeout("alert(3)",3000)});
    ...

    可是 1, 2, 3 是一块弹出来的 并不是每隔3秒弹一次...
    这是怎么回事啊...
      回复  引用  查看    
  2. #2楼[楼主] Cat Chen      2009-10-19 16:29
    在next里面的异步函数,必须是返回Async.Operation对象的,才会按照阻塞的方式执行。例如:

    chain.next(function(){
    var operation = new Async.Operation();
    setTimeout(function(){ operation.yield("hello"); }, 3000);
    return operation;
    })

    接着你可以再next一下来接收:

    chain.next(function(result){
    alert(result); // should be "hello"
    });
      回复  引用  查看    
  3. #3楼 普通男孩      2009-10-20 10:12
    这回可以了.十分感谢啊,呵呵.不过...还有个问题...
    http://www.cnblogs.com/cathsfz/archive/2009/07/01/1514983.html
    上面这个地址有个延时函数,我是这么写的...

    ...
    var chain = Async.chain();
    alert(typeof chain.wait);//output function
    for(var i = 0; i < 5; i++){
    chain
    .wait(1000)
    .next(function() {
    var operation = new Async.Operation();
    setTimeout(function() {
    alert(1);
    operation.yield("rst");
    }, 2000);
    return operation;
    })
    }
    ...
    很奇怪的是 我在第二行alert的时候可以打印 function, 但是后面就出错了.
    我用的是火狐,它的控制台里面报"chain.wait(1000) is undefined",这是怎么回事啊,还有我这么调用对吗?
      回复  引用  查看    
  4. #4楼[楼主] Cat Chen      2009-10-20 11:18
    @普通男孩
    不好意思,是我手误,在wait里面忘记写return了,所以wait().next()后面的next会出错。你可以自行在wait函数里补上return。
      回复  引用  查看    
  5. #5楼 普通男孩      2009-10-20 15:21
    已经可以了,多谢.
    很不错的框架,你的博客我收藏了,以后就跟你混了,呵呵.
      回复  引用  查看    
  6. #6楼[楼主] Cat Chen      2009-10-20 15:40
    @普通男孩
    :)
      回复  引用  查看    
  7. #7楼 普通男孩      2009-10-23 13:35
    哦 对了.
    在wait(1000) 后面我加了 .yield() 才继续执行.不加好像不行...

    还有...

    if (chain) {
    callbackResult = callback(self.result);
    ...

    这个callbackResult 为什么是全局的啊....我加了个var好像也可以...
      回复  引用  查看    
  8. #8楼[楼主] Cat Chen      2009-10-23 22:45
    @普通男孩
    第一个问题我现在比较难确定,因为我手上的版本已经和写文章时的版本有一定的差别了,而现在的版本fix了一些bug。我懒得手动维护文章里面的代码了,考虑将来直接把新版本发布到一个公开的SVN吧,你有任何建议吗?

    第二个问题,其实这个没有var的东西,在找不到更大的scope中有var过的前提下,就相当于本scope内var了。这里确实是我漏写var了,更严谨的写法应该是有var的。
      回复  引用  查看    
  9. #9楼 普通男孩      2009-11-02 09:21
    这两天不舒服也没上来看,不好意思...好没问题,希望你的正式版尽快出来,呵呵.

    "第二个问题,其实这个没有var的东西,在找不到更大的scope中有var过的前提下,就相当于本scope内var了。这里确实是我漏写var了,更严谨的写法应该是有var的。"
    ...
    function a()
    {
    c = 1;
    }
    function b()
    {
    alert(c);
    }
    ...
    先执行了a方法后,再执行b方法,c就有值了...貌似如果不写var就表示它是全局(window)的对象
      回复  引用  查看    
  10. #10楼[楼主] Cat Chen      2009-11-02 14:01
    @普通男孩
    确实,在没有var的时候,自动把scope放大到window。
      回复  引用  查看