如何在 Javascript 中支持 2 种类型的回调
How to support 2 types of callback in Javascript
在 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
});
我的问题是:intercom
如何知道我是通过 funcrtion(err,d)
还是只是 function(data)
。
我查看了源代码,发现他们使用了bluebird
库。蓝鸟是怎么做到的?
我希望我的函数也能做同样的事情。
换句话说:
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.
请注意:这是不好的做法。您应该为接受的回调提供统一的签名。 (err, data) => {}
是一个很好的签名。
或者更好的是,让你的 list()
函数 return 成为一个 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 );
});
在 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 });
我的问题是:intercom
如何知道我是通过 funcrtion(err,d)
还是只是 function(data)
。
我查看了源代码,发现他们使用了bluebird
库。蓝鸟是怎么做到的?
我希望我的函数也能做同样的事情。
换句话说:
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.
请注意:这是不好的做法。您应该为接受的回调提供统一的签名。 (err, data) => {}
是一个很好的签名。
或者更好的是,让你的 list()
函数 return 成为一个 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 );
});