防止多次绑定函数



我有一个递归重试例程,如下所示:

Foo.prototype.retry = function(data, cb){
cb && (cb = cb.bind(this));  // want to bind the cb fn just once
this.resolutions[x] = (err, val) => {
if(val === 'foobar'){
// in this case, we do a retry
return this.retry(data, cb);
}
}:
}

如您所见,在某些情况下,我会通过再次调用this.run来重试。但我想避免不止一次地打电话给cb.bind()。有什么好方法可以做到这一点吗?

=> 我的意思是,有没有办法以某种方式检查函数是否绑定到某个this值?

我知道的唯一好的解决方案是通过重试计数,如下所示:

Foo.prototype.retry = function(data, cb){
if(cb){
if(!data.__retryCount){
cb = cb.bind(this);
}
}
this.resolutions[x] = (err, val) => {
if(val === 'foobar'){
// we do a retry here
data.__retryCount = data.__retryCount || 0;
data.__retryCount++;
return this.retry(data, cb);
}
}:
}

你可以对绑定版本使用局部变量,这样当你递归地调用自己时,你会传递原始cb,而不是绑定的:

Foo.prototype.run = function(data, cb){
let callback = (cb && cb.bind(this)) || function() {};
this.resolutions[x] = (err, val) => {
if(val === 'foobar'){
// we do a retry here and pass original cb
return this.run(data, cb);
}
};
// then elsewhere in this function when you want to use the bound one, use callback()
}

或者,如果你真的只想绑定它一次,那么你可以在包装函数中执行此操作,并通过假设回调已经绑定的子函数递归地调用自己:

// internal function, assumes callback is already bound
Foo.prototype._run = function(data, cb){
// cb is already bound here
this.resolutions[x] = (err, val) => {
if(val === 'foobar'){
// we do a retry here
return this._run(data, cb);
}
}
}
// bind the callback and then call our internal function
Foo.prototype.run = function(data, cb){
let callback = (cb && cb.bind(this)) || function() {};
return this._run(data, callback);
}

您可以创建一个类变量来指示函数是否已绑定:

let Foo = function() {
this.resolutions = [];
};
Foo.prototype.run = function(data, cb) {
if (!this.bound) {
console.log('binding');
cb && (cb = cb.bind(this));
this.bound = true;
}
this.resolutions[x] = (err, val) => {
if (val === 'foobar') {
// we do a retry here
return this.run(data, cb);
}
};
};
console.log('x');
let x = new Foo();
x.run();
console.log('y');
let y = new Foo();
y.run();
console.log('x');
x.run();

由于绑定会掩盖 Function.toString(( 方法中的原始纯文本函数源代码,因此您可以检查字符串版本以查看是否已绑定用户 land 函数:

if(!/[native code]/.test(cb)) cb = cb.bind(this);

请注意,您不能在已经原生的方法(如console.logwindow.alert(上使用此方法,但这对您的用例来说可能不是问题。

整体:

Foo.prototype.retry = function(data, cb){
if(!/[native code]/.test(cb)) cb = cb.bind(this); //  bind the cb fn just once
this.resolutions[x] = (err, val) => {
if(val === 'foobar'){
// in this case, we do a retry
return this.retry(data, cb);
}
}
};

最新更新