如何在Javascript中支持2种types的callback

intercom-client github中,我看到了这个代码:

 client.users.list(function (d) { // d is the response from the server }); // Or client.users.list(function (err, d) { // err is an error response object, or null // d is a successful response object, or null }); 

我的问题是:如何通过funcrtion(err,d)或只是function(data)知道intercom

我检查了源代码,发现他们使用bluebird库。 蓝鸟如何做呢?

我希望我的function也能做到这一点。

换一种说法:

 function myFunction(data,callback){ if (callbackListenToErrArgument(callback)) callback(null,data) else callback(data) } 

如何实现callbackListenToErrArgument函数?

可以检查函数通过的.length属性。 .length属性是为函数定义的参数个数。

 function hasErrorArgument(callback) { if (callback.length < 2) { return false; } // Has 1 or 0. else return true; // has 2 or more } // Yes, I know it can be reduced to one line. Sue me. 

请注意:这是不好的做法。 你应该为你接受的callback提供统一的签名。 (err, data) => {}是一个很好的签名。

或者更好的办法是让你的list()函数返回一个Promise对象:( Promise本身仅支持在某些浏览器中使用,在使用前检查兼容性,或者使用polyfill或者库)。

 client.users.list() .then(listOfUsers => { // Use data here }) .catch(err => { // Handle errors here }); 

假设看方法长度:

 fun=function(a,b,c) { console.log(a,b,c) } (a,b,c) { console.log(a,b,c) } fun.prototype.constructor.length 3 

可以被认为是一个不好的做法,如@ madara-uchiha所述, bluebird库有一个方法调用函数,它是:

 var makeMethodCaller = function (methodName) { return new Function("ensureMethod", " \n\ return function(obj) { \n\ 'use strict' \n\ var len = this.length; \n\ ensureMethod(obj, 'methodName'); \n\ switch(len) { \n\ case 1: return obj.methodName(this[0]); \n\ case 2: return obj.methodName(this[0], this[1]); \n\ case 3: return obj.methodName(this[0], this[1], this[2]); \n\ case 0: return obj.methodName(); \n\ default: \n\ return obj.methodName.apply(obj, this); \n\ } \n\ }; \n\ ".replace(/methodName/g, methodName))(ensureMethod); }; 

[更新]我已经添加了一个Bluebird代码的工作片断来讨论它。 正如有人所说,这似乎是适用于其他事情,即使在开关柜中有一个方法长度的后卫。 检查代码:

 var console={} console.log=function(msgs) { document.writeln(msgs)}; var makeMethodCaller = function (methodName) { return new Function("ensureMethod", " \n\ return function(obj) { \n\ var len = this.length; \n\ console.log(\"Who is this\"+this); \n\ ensureMethod(obj, 'methodName'); \n\ switch(len) { \n\ case 1: return obj.methodName(this[0]); \n\ case 2: return obj.methodName(this[0], this[1]); \n\ case 3: return obj.methodName(this[0], this[1], this[2]); \n\ case 0: return obj.methodName(); \n\ default: \n\ return obj.methodName.apply(obj, this); \n\ } \n\ }; \n\ ".replace(/methodName/g, methodName))(ensureMethod); }; function ensureMethod(obj, methodName) { var fn; if (obj != null) fn = obj[methodName]; if (typeof fn !== "function") { var message = "Object " + JSON.stringify(obj) + " has no method '" + JSON.stringify(methodName) + "'"; throw new Error(message); } return fn; } var fn=makeMethodCaller("callMe"); console.log(fn) var obj0= { callMe : function() { console.log("\n\n\ncalled with 0 params")} }; var obj1= { callMe : function(a) { console.log("\n\n\ncalled with 1 params")} }; var obj2= { callMe : function(a,b) { console.log("\n\n\ncalled 2 params")} }; var obj3= { callMe : function(a,b,c) { console.log("\n\n\ncalled 3 params")} }; [obj0,obj1,obj2,obj3].map(function(e) { return fn( e ); }); 
Interesting Posts