`
yiminghe
  • 浏览: 1430003 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

continuation, cps

阅读更多

  随着 nodejs 的兴起,异步编程成为一种潮流,而异步也对编程风格带来了一些影响,典型的比如在客户端尚不明显的 cps 风格的大量出现:

 

getUser(function(){
   // ....
   getItem(function(){
    // ...
    });
})

 

  回调嵌套带来性能,栈溢出,以及代码阅读上的一系列的问题,目前有不少解决方案,比如 promise 或引入新的编程原语. 但本次要介绍的是在上世纪60年代就提出来的一个概念 continuation,用来解决该问题。

 

  continuation 是一种表达范围更广的概念,可用于实现 closure,generator 等动态语言常见的特性,甚至 goto ,而支持的语言也比较少,恰好 rhino 实现了 continuation,因此可以在 javascript 上做下演示,对比下传统的回调实现。

 

  常见应用场景: 异步执行某些操作后再进行返回结构处理,一般实现如下(不解释):

 

 

function doSomethingAsynchronously(callback) {
    var t = new java.lang.Thread(new java.lang.Runnable() {
        run: function () {
            try {
                java.lang.Thread.sleep(1000);
            } catch (e) {
                print(e);
            }
            callback(1);
        }
    });
    t.start();
}

var cont = doSomethingAsynchronously(function (x) {
    print(x);
});

 

 

  可以看到已经引入了一个回调函数用来接收异步结果,即 cps 风格。  

 

  而如果用 continuation 来实现的话则是另外一种风格:

  

 

function makeRequest(cont) {
    var t = new java.lang.Thread(new java.lang.Runnable() {
        run: function () {
            try {
                java.lang.Thread.sleep(1000);
            } catch (e) {
                print(e);
            }
            cont(1);
        }
    });
    t.start();
}

function getContinuation() {
    return new Continuation();
}

function doSomethingAsynchronously() {
    var x = 1;
    var cont = getContinuation();
    if (cont instanceof Continuation) {
        x = 2;
        makeRequest(cont);
    } else {
        print('run');
        cont += x;
    }
    return cont;
}

var cont = doSomethingAsynchronously();
if (typeof cont == 'number') {
    print(cont);
}

 

 

 其中 new Continuation() 产生一个 continuation 可调用对象,这个对象封装了当前代码执行处以及上下文(注意 rhino 记录的是 new Continuation() 所在函数的位置),当调用 continuation 对象后则相当于一个增强的 goto 调用,回到产生 continuation 对象的调用点,恢复上下文,并把参数值作为 continuation 对象的值后执行。

 

 continuation 不仅可以解决 cps 带来的问题,也可以解决目前 web 开发多页面跳转无状态所带来的逻辑代码分散的问题(个人建议单页面 javascript 控制),在java端有 cocoon 框架(结合 rhino ),可以使用 continuation 记录上下文来达到传统客户端的开发体验:

  

 

function calculator() {
    var a, b, operator;

    cocoon.sendPageAndWait("getA.html");
    a = cocoon.request.get("a");

    cocoon.sendPageAndWait("getB.html");
    b = cocoon.request.get("b");

    cocoon.sendPageAndWait("getOperator.html");
    operator = cocoon.request.get("op");
}

 

 

  continuation 虽然有不少优点,但由于过于灵活,强大也会导致一些其他问题,例如 continuation 实现需要比 closure 记录更多的上下文信息,可能会对运行效率造成影响。另外如果滥用会造成 goto 语句一样的问题。

 

  continuation 是一个表达力很强的功能,合理利用后能够形成新的编程风格从而改善可读性,维护性等问题,而随着 es6 generator 等的实现,javascript 也将受益。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics