通用包装协调functionasynchronous风格

我很想写一个通用的包装函数,并返回该函数的“asynchronous风格”版本, 如果它不是开始的asynchronous。

麻烦的是,没有简单的方法来知道这个调用是同步的还是asynchronous的。 所以…这基本上“不能做”。 对?

(请注意,包装应协调同步函数为asynchronous风格,并单独离开asynchronous函数)

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

在JavaScript中,没有办法检查一个函数的最后一个参数是否是一个函数,因为在JavaScript中你没有定义你的参数的types。

我的解决scheme通过获取函数中的参数列表,然后使用RegExp来查看该参数是否被用作函数。 另外,在callback没有被直接使用的情况下(比如把它传递给别的东西),它有一个参数名称列表被视为callback。

代码是:

 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) ,它将返回一个asynchronous函数。 这将工作,如果你使用function.apply.call

你不能找出一个函数接受的参数是什么,所以你不能找出是否需要callback。

它根本无法完成。 故事结局。

虽然,这不是答案,但是一个好的select。 我提供了基于浏览器的JavaScript示例,但同一类也可以在Node上使用。

为了解决这个问题,承诺开发了。 但是,我们使用承诺的修改版本如下。

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

这两个函数现在是asynchronous的。 Push Value方法通过setTimeout生成结果路由,使进一步的调用asynchronous。

这是在Web Atoms JS中使用的asynchronous代码到单个属性,并通过遵循一个模式,你可以摆脱asynchronouscallback地狱。 http://webatomsjs.neurospeech.com/docs/#page=concepts%2Fatom-promise.html

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