防止多次绑定函数

时间:2017-07-25 22:52:10

标签: javascript node.js

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

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

       }:

    }

3 个答案:

答案 0 :(得分:4)

您可以使用局部变量作为绑定版本,因此当您以递归方式调用自己时,您将传递原始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);
}

答案 1 :(得分:2)

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



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




答案 2 :(得分:1)

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

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