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
。