我正在尝试创建一个小实用程序函数toPromise
,它使用回调将函数转换为promise函数(使用Q)。
这是实用程序:
Object.defineProperty(Function.prototype, "toPromise", {
enumerable: false,
configurable: false,
writable: false,
value: function(self) {
var $this;
$this = this;
return function() {
var args, deferred;
deferred = Q.defer();
args = arguments;
args[args.length] = deferred.resolve;
console.dir(args);
$this.apply(self, args);
return deferred.promise;
};
}
});
以下是用法:
var f = function(nickname, name, callback){
console.log(arguments)
callback(undefined, name+" "+nickname);
};
f.toPromise(this)("a", "b").then(function(str){
console.log(str)
});
但输出是:
{ '0': 'a', '1': 'b', '2': [Function] } // This is debugging from utils
{ '0': 'a', '1': 'b' } // and from the function f
C:\test.js:4
callback(undefined, name+" "+nickname);
^
TypeError: undefined is not a function
那么为什么第三个arg(在utils中)函数没有传递给apply
?
答案 0 :(得分:2)
arguments
对象不是真正的数组:
>>> function getArguments() { return arguments; }
>>> var a = getArguments(1,2,3), b = [1,2,3];
>>> a[3] = 4; b[3] = 4;
>>> a
[1, 2, 3]
>>> b
[1, 2, 3, 4]
>>> a.length
3
>>> b.length
4
因此,如果您打算修改它或将其传递到函数外部,最好将其转换为真实数组:
var args = Array.prototype.slice.call(arguments);
答案 1 :(得分:2)
您确实已将回调分配给arguments
object,但由于它不是一个不会自动增加其length
属性的实际数组。如果length
仍为2
,则只会在apply
中跳过您的回调。
修复很简单:
Function.prototype.toPromise = function(self) {
var fn = this;
return function() {
var deferred = Q.defer();
arguments[arguments.length++] = deferred.resolve;
// ^^
fn.apply(self||this, arguments);
return deferred.promise;
};
};
您也可以使用Array.prototype.push.call(arguments, deferred.resolve)
。请注意Q
already provides such similar1 a functionality(可能已经优化了效率),所以如果您只是想在原型上使用它,那么最好做
Function.prototype.toPromise = function(self) {
return Q.nbind(this, self);
};
1:请注意resolve()
不接受错误参数,例如" nodebacks"通常做