登录
注册
node.js 学习社区
SyncCallback 同步方式书写异步代码

陈伟钦

2014-12-17 21:02

SyncCallback

先看用法

首先注册你的方法是通过拦截改写的

 SyncCallback.register(this,__test.main,'main');return;

调用的方法名必须带有 callback_ 标识

var callresult= this.callback_();

await: endawait; 组合声明

await: 
var callresult= this.callback_();
//code
endawait;

下面是简单的示例

var __test = {
 callback_test1 : function(callback){
  var result = ' callback_test1 result value';
  setTimeout(function(){
     callback(result);
  },10000);
 },
 callback_test2 : function(p1,callback){
  var result = ' callback_test1 result value';
  setTimeout(function(){
    callback(result);
  },10000);
 },
 main : function(){ 
  //register 
  SyncCallback.register(this,__test.main,'main');return;

    //test
  await: 
   var value = this.callback_test1();
   var localvalue = "localvalue";
   await: 
    var value2 = this.callback_test2(value);

    console.log(" test callback1 ===================", value);
    console.log(" test callback2 ===================", value2);
    console.log(" test callback3 localvalue ===================", localvalue);
   endawait;
   await: 
    var value2 = this.callback_test2(value);
    console.log(" test callback2 ===================", value2);
   endawait;
  endawait;
 }
}

//static test
__test.main();
__test.main();

//动态类 test
function testsync(){
 this.abc = "xxx";
}
testsync.prototype.test = function(v){
 //register 
  SyncCallback.register(this,this.test,'test');return;    

 //test
 await: 
  var value = __test.callback_test1();
  var localvalue = "localvalue";
  await: 
   var value2 = __test.callback_test2(value);

     console.log(" test callback3 localvalue ===================", localvalue);
  endawait;
  await: 
   var value2 = __test.callback_test2(value);
   console.log(" test callback2 ===================", value2);
  endawait;
 endawait;    
};

new testsync().test("v");

下面是介绍整个写作过程

fn1(function(){
    fn2(function(){
        fn3(function(){
            fn4();
            .....
        });
    });
});

写过JS的人都知道上面的代码是多头痛,第二次看肯定有想死的感觉 假如代码变成这样

var v1= callback_fn1();
var v2= callback_fn2(v1);
var v3= callback_fn3(v2);

//以上是程序未运行时的代码
//通过拦截进行改写

//第一次改写
var v1= callback_fn1(function(v1){
    var v2= callback_fn2(v1);
    var v3= callback_fn3(v2);
});
//第二次改写
var v1= callback_fn1(function(v1){
    var v2= callback_fn2(function(v2){
        var v3= callback_fn3(v2);
    });
});
//第三次改写 最终代码变成这样
var v1= callback_fn1(function(v1){
    var v2= callback_fn2(function(v2){
        var v3= callback_fn3(function(v3){

        });
    });
});

以上是写代码的想法过程,或者说是原理
第一版本有个缺点,就是不知道什么情况下结尾 })
所有直接在代码后面按次数补上

var _injection_end ="})";
while(i>0){
 i--;
 codestring += _injection_end;     
}

直接昨天学习 b语言的时候,发现 start end; 声明
今早起来突然觉得这个可以用上,就变成

var _injection_end ="})";
codestring = codestring.replace(/await\s*\:/mg,'');
codestring = codestring.replace(/endawait\s*;/mg,_injection_end);

目前不支持

if(this.callback())

如果有这种逻辑,请写成
var value = this.callback();
if(value){

}

缺点

要先注册才能使用

调用的方法名要声明 callback_ 为什么这看下具体实现,希望谁有好的方法,或者正则强大的话,改写一下

核心文件

/**
 * @author solq
 * @deprecated blog: cnblogs.com/solq
 * */
//www.springnodejs.com

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 


var SyncCallback = {

 /**
  * @param callObj 注册对象
  * @param fn 注册方法 
  * @param fnName 注册名
  * */
  //public
 register : function(callObj,fn,fnName){
  if(typeof fn != 'function'){
   return;
  }
   if( fnName==''){
   return;
  }
  var key ='__overrideFunction_' + fnName;

  if(callObj[key]!=null){
   var params = this.getParamNames(callObj[key]);
   callObj[key].apply(callObj,params);
   //console.log("double run");

   return;
  }

  this._aop(key,fn,callObj); 
 },
 scanMarker : 'callback_',    //简单的判断扫描方式

 /**
  * aop 拦截
  * @param container 注册对象
  * @param fn 注册方法 
  * @param fnName 注册名
  * */
 //private
 _aop : function(fnName,fn,container){ 
  //scan code
  //injection code
  //overrideFunction 
  var codestring = this._scanCode(fn);
   if(codestring.indexOf( this.scanMarker) <0 ){
   return;
  }

  //console.log("first run");
   var new_codestring = this._injectionCode(codestring);
  var params = this.getParamNames(fn);
  var newFuntion = this._overrideFunction(new_codestring,params);     
  container[fnName]=newFuntion;     
  container[fnName].apply(container,params);
  },    
 /**
  * 获得方法参数
  * */
 getParamNames : function(func) {
  var fnStr = func.toString().replace(STRIP_COMMENTS, '')
  var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(/([^\s,]+)/g)
  if(result === null)
   result = []
  return result
 },
 /**
  * 扫描方法 code
  * */
 _scanCode : function(fn){     
  var code=fn.toString().replace(STRIP_COMMENTS, '');
  return code.substring(code.indexOf('{')+1, code.lastIndexOf('}'));
  },
 /**
  * 注入增强代码
  * */
 _injectionCode : function(codestring){
  var _injection_start ="var __$this = this;";
   var _injection_end ="})";

  //var i = 0 ;
  codestring = codestring.replace(/var\s+(.*)\=.*callback_[^\)]+(.*)/mg,function(a,b,c,d){
   //debug("codestring replace ==============",a," b====== ",b," c=============== ",c, " d============== ",d);
   //i++;    

   var _injection_code ="function("+b+"){";
    var result =a.replace(/\((.*)\)/,function(pa,pb){
    var r ;
    if(pb.trim()==''){
     r = "("+_injection_code;
    }else{
     r = "("+pb+","+_injection_code;
    }
     return r;
   });
   //debug("result ====================",result);
   return result;
  });

  //第一版本替换
  /*
  while(i>0){
   i--;
   codestring += _injection_end;     
  }*/
  //第二版本替换
  codestring = codestring.replace(/await\s*\:/mg,'');
  codestring = codestring.replace(/endawait\s*;/mg,_injection_end);

  //replace this
  codestring = codestring.replace(/this\s*\./mg,'__$this.');
  codestring = _injection_start + codestring;
  codestring = codestring.replace(/SyncCallback\.register\(.*\);\s*return/mg,'');
  //console.log("new code ==============",codestring);
  return codestring;
 },
 /**
  * 重写方法
  * */
 _overrideFunction : function(new_codestring,params){
  if(params.length==0){
   return new Function(new_codestring);
  }     
  return new Function(params,new_codestring);
 },
};

原文引自:http://cnodejs.org/topic/532fe1797ab0bd860c018b06

回复 · 0

发表回复

你可以在回复中 @ 其他人