2017-07-25 5 views
1

Ich habe eine rekursive Wiederholungsroutine, so etwas wie dieses:Prevent Bindung eine Funktion mehr als einmal

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

    }: 

} 

, wie Sie unter bestimmten Umständen sehen können, ich durch den Aufruf this.run wieder wiederholen wird. Aber ich möchte vermeiden, cb.bind() mehr als einmal zu nennen. Gibt es einen guten Weg, das zu tun?

=> Was ich meine, gibt es eine Möglichkeit, irgendwie zu überprüfen, eine Funktion ist an einen bestimmten this Wert gebunden?

Die einzige gute Lösung, die ich kenne, ist eine Wiederholungsanzahl zu übergeben, etwa so:

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

     }: 

    } 
+2

warum die downvote? Bitte erklären Sie, warum Sie die Frage nicht mögen –

+0

ist 'cb? (cb = cb.bind (this)) 'gültige JS? Ich wusste nicht, dass Sie ein ternäres ohne eine alternative definiert –

+2

ich cb && nicht cb?, Sorry typo –

Antwort

2

Sie können eine Klassenvariable erstellen, die anzeigt, ob die Funktion gebunden ist:

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

+0

wird in diesem Fall nicht funktionieren, da dies eine Klasse mit vielen Instanzen ist, muss ich einen Boolean für jede Klasseninstanz erstellen. –

+1

@AlexanderMills, das wäre ein guter Kontext gewesen, um in Ihre Frage aufzunehmen. –

+0

Dann machen Sie die Variable eine Eigenschaft –

4

Sie können so eine lokale Variable für die gebundene Version verwenden, wenn Sie sich selbst rekursiv aufrufen, übergeben Sie die ursprüng l cb, nicht die gebundene ein:

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

Oder, wenn Sie wirklich nur sie jemals binden einmal wollen, dann können Sie in einer Wrapper-Funktion tun, dass Sie sich und rufen rekursiv über eine Unterfunktion, die der Rückruf annimmt bereits gebunden:

// 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); 
} 
+0

das würde funktionieren :) gutes Denken –

+0

@AlexanderMills - Ich fügte eine weitere Option hinzu. – jfriend00

+0

Vielen Dank für Ihre Arbeit hier –

1

Da die Bindung die ursprüngliche Klartext-Funktion Quellcode aus dem Function.toString() -Methode verschleiert, können Sie die String-Version überprüfen, ob eine Benutzer-Land-Funktion zu sehen war gebunden:

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

Hinweis: Sie können nicht diesen Ansatz auf bereits native Methoden wie console.log oder window.alert, aber das ist wahrscheinlich kein Problem für Ihren Anwendungsfall.

ganz:

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