Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 将函数协调为异步样式的通用包装器_Node.js_Asynchronous - Fatal编程技术网

Node.js 将函数协调为异步样式的通用包装器

Node.js 将函数协调为异步样式的通用包装器,node.js,asynchronous,Node.js,Asynchronous,我很想编写一个通用包装器,它接受一个函数,并返回该函数的“异步样式”版本,如果它一开始不是异步的 问题是,没有简单的方法可以知道调用是同步的还是异步的。所以这基本上是“无法做到的”。对吧? (请注意,包装器应将同步函数协调为异步样式,而不使用异步函数) 这根本无法做到。故事结束。您无法找到函数的可接受参数是什么,因此无法确定它是否接受回调。在javascript中,无法检查函数的最后一个参数是否是函数,因为在javascript中,您没有定义参数的类型 我的解决方案是获取函数中的参数列表,然后使

我很想编写一个通用包装器,它接受一个函数,并返回该函数的“异步样式”版本,如果它一开始不是异步的

问题是,没有简单的方法可以知道调用是同步的还是异步的。所以这基本上是“无法做到的”。对吧?

(请注意,包装器应将同步函数协调为异步样式,而不使用异步函数)


这根本无法做到。故事结束。

您无法找到函数的可接受参数是什么,因此无法确定它是否接受回调。

在javascript中,无法检查函数的最后一个参数是否是函数,因为在javascript中,您没有定义参数的类型

我的解决方案是获取函数中的参数列表,然后使用RegExp查看该参数是否用作函数。此外,在回调没有被直接使用的情况下(比如将其传递给其他对象),它有一个参数名列表,可以被视为回调

代码是:

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var CALLBACK_NAMES = [ "next", "done", "callback", "cb"];

function getParamNames(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
}

function checkIfParamIsFunction(func, paramName){
  var fnStr = func.toString();
  if (fnStr.replace(new RegExp("(" + paramName + "\s*\([A-Za-z0-9,\.]*\)?!{|" + paramName + ".apply\([A-Za-z0-9,\.]*\)|" + paramName + ".call\([A-Za-z0-9,\.]*\))", ""), "{<._|/}") != fnStr) { // Remove All Calls to the arg as a function, then check to see if anything was changed.
    return true;
  } else {
    return false;
  }
}


function makeAsync(func) {
  var paramNames = getParamNames(func);
  if (checkIfParamIsFunction(func, paramNames[paramNames.length - 1]) 
  || CALLBACK_NAMES.indexOf(paramNames[paramNames.length - 1]) != -1) {
    // Function Is Already async
    return func;
  } else {
    return function () {
      var args = Array.prototype.slice.call(arguments);
      var cb = args.pop();
      cb(func.apply(this, args));
    }
  }
}

function test1(a){
  return (a+' test1');
};

function test2(a, callback){
  return callback(a+' test2')
};

function main(){
  var tested1 = makeAsync(test1);
  var tested2 = makeAsync(test2);
  tested1('hello', function(output){
    console.log('holy shit it\'s now async!!');
    console.log(output);
  });
  tested2('world', function(output){
    console.log('this one was already async tho');
    console.log(output);
  });
}

main();
var STRIP\u COMMENTS=/(\/\/.$)|(\/\*[\s\s]*?\*\/)/mg;
var CALLBACK_name=[“下一步”、“完成”、“回调”、“cb”];
函数getParamNames(func){
var fnStr=func.toString().replace(带注释“”)
var result=fnStr.slice(fnStr.indexOf('(')+1,fnStr.indexOf(')).match(/([^\s,]+)/g)
如果(结果===null)
结果=[]
返回结果
}
函数checkIfParamIsFunction(func,paramName){
var fnStr=func.toString();

if(fnStr.replace(new RegExp)(“+paramName+”\s*\([A-Za-z0-9,\.]*\)?!{{124;“+paramName+”。apply\([A-Za-z0-9,\.]*\)“+paramName+”。call\([A-Za-z0-9,\.]*\)”),“),”,“{虽然这不是答案,但是一个很好的选择。我提供了基于浏览器的JavaScript示例,但同样的类也可以在Node上使用

为了解决这个问题,我们开发了promise

function AtomPromise(f)
{ 
   // Success callbacks
   this.sc = [];
   // Error callbacks
   this.ec = [];
   this.i = f;
   this.state = 'ready';
}

AtomPromise.prototype ={
   finish: function(s,r) {
      this.result = r;
      var c = s ? this.sc : this.ec;
      this.state = s ? 'done' : 'failed' ;
      for(var i=o ; i< c.length; i++){
          c[i](this);
      }
   },
   invoke: function(f) {  
      this.state = 'invoking';
      this.i(this);
   },
   then: function(f) {
      this.sc.push(f);
   },
   failed: function(f){
      this.ec.push(f);
   },
   value: function(v) {    
      if(v !== undefined ) this.result = v;
      return this.result;
   },
   pushValue: function(v) {
      var _this = this;
      setTimeout(100, function () { 
         _this.finish(true, v);
      });
   }
}



//wrap jQuery AJAX
AtomPromise.ajax = function( url, options ) {
   return new AtomPromise(function (ap){ 
      $.ajax(url, options)
         .then( function(r){ ap.finish(true, r); })
         .failed( function (){ ap.finish( false, arguments) });
   }) ;
}

//Wrape sync function
AtomPromise.localStorage = function( key ) {
   return new AtomPromise(function (ap){ 
      var v = localStorage[key];
      ap.pushValue(v);
   }) ;
}



// Calling Sequence

AtomPromise.ajax( 'Url' ).then( function(ap) {
   alert(ap.value());
}).invoke();

AtomPromise.localStorage( 'Url' ).then( function(ap) {
   alert(ap.value());
}).invoke();
函数自动编程(f)
{ 
//成功回调
this.sc=[];
//错误回调
this.ec=[];
这个,i=f;
this.state='ready';
}
原型={
完成:功能(s、r){
结果=r;
var c=s?this.sc:this.ec;
this.state=s“完成”:“失败”;
对于(变量i=o;i
这两个函数现在都是异步的。Push-Value方法使结果路由通过setTimeout,从而使进一步的调用异步

这在Web Atoms JS中用于将异步代码包装成单个属性,通过遵循一种模式,您可以摆脱异步回调地狱


免责声明:我是Web Atoms JS的作者。

很多人抱怨node中的回调地狱。很有意思的是,有人非常喜欢回调,以至于他们也想将回调添加到同步函数中:)获取最后一个参数的参数名可能会很有意思。然后可以检查参数,看看它们是否符合标准回调模式?@Plato如果不显式传递函数的参数,您如何从外部检查函数的参数。您必须传递函数的参数。您认为如何?如果我知道ew如何做到这一点我会自己回答的!可能是一些涉及到字符串化函数和查看字符串中的参数名称的魔法,并查看函数体是否使用
argName(…)调用它们
或其他什么第一个
if/else
块后有一个额外的括号,并且
checkIfParamIsFunction
未定义,第3行
paramName
将未定义;您是否缺少顶部附近的函数定义?@Plato,是的,谢谢splato,您对答案满意吗?我是否接受正确的答案一个(似乎是)?赏金在4小时后到期…我做了一些编辑,包括测试代码和更正打字错误。这很有效,万岁!我知道必须有一些黑客才能完成!函数makeAsync似乎定义了两次…?底部的调用序列看起来很干净。为什么必须使用
设置超时
?你不能简单地调用
>ap.finish(true,v)
而不是
ap.pushValue(v)
?毫秒参数也应该是秒:
setTimeout(fn,100)
我已经解释过,我使用pushValue的原因是为了使它真正异步,这意味着它将在以后使用不同的堆栈调用,调用ap.finish将在同一堆栈上调用,但这取决于您。
function AtomPromise(f)
{ 
   // Success callbacks
   this.sc = [];
   // Error callbacks
   this.ec = [];
   this.i = f;
   this.state = 'ready';
}

AtomPromise.prototype ={
   finish: function(s,r) {
      this.result = r;
      var c = s ? this.sc : this.ec;
      this.state = s ? 'done' : 'failed' ;
      for(var i=o ; i< c.length; i++){
          c[i](this);
      }
   },
   invoke: function(f) {  
      this.state = 'invoking';
      this.i(this);
   },
   then: function(f) {
      this.sc.push(f);
   },
   failed: function(f){
      this.ec.push(f);
   },
   value: function(v) {    
      if(v !== undefined ) this.result = v;
      return this.result;
   },
   pushValue: function(v) {
      var _this = this;
      setTimeout(100, function () { 
         _this.finish(true, v);
      });
   }
}



//wrap jQuery AJAX
AtomPromise.ajax = function( url, options ) {
   return new AtomPromise(function (ap){ 
      $.ajax(url, options)
         .then( function(r){ ap.finish(true, r); })
         .failed( function (){ ap.finish( false, arguments) });
   }) ;
}

//Wrape sync function
AtomPromise.localStorage = function( key ) {
   return new AtomPromise(function (ap){ 
      var v = localStorage[key];
      ap.pushValue(v);
   }) ;
}



// Calling Sequence

AtomPromise.ajax( 'Url' ).then( function(ap) {
   alert(ap.value());
}).invoke();

AtomPromise.localStorage( 'Url' ).then( function(ap) {
   alert(ap.value());
}).invoke();