5

関数を受け取り、最初から非同期ではない場合、その関数の「非同期スタイル」バージョンを返す汎用ラッパーを書きたいと思います。

問題は、呼び出しが同期か非同期かを簡単に知る方法がないことです。ということで・・・これは基本的に「できません」。右?

(ラッパーは同期関数を非同期スタイルに調和させ、非同期関数をそのまま残す必要があることに注意してください)

var wrapper = function( fn ){

    return function(){
      var args = Array.prototype.splice.call(arguments, 0);

      var cb = args[ args.length - 1 ];

      // ?!?!?!?!?
      // I cannot actually tell if `fn` is sync
      // or async, and cannot determine it!    

      console.log( fn.toString() );
    }
}

var f1Async = wrapper( function( arg, next ){
  next( null, 'async' + arg );
})

var f2Sync = wrapper( function( arg ){
  return 'sync' + arg;
})


f1Async( "some", function(err, ret ){
  console.log( ret );
});


f2Sync( "some other", function(err, ret ){
  console.log( ret );
});
4

4 に答える 4

1

それは単に行うことはできません。話の終わり。

于 2013-10-31T05:29:15.997 に答える
1

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();

呼び出すだけmakeAsync(function)で、非同期関数が返されます。function.applyまたはを使用すると、これが機能します.call

于 2013-11-09T01:43:40.007 に答える