2013-02-10 14 views
5

Widziałem kilka bitów kodu niedawno, że wyglądają tak:Dodać następnie metodę funkcji do wywołania zwrotne

myFunc(args).then(function() { ... }); 

Uważam to składnia zwrotna naprawdę elegancki. Rozumiem, że nie jest to część JS vanilla i chciałbym móc go używać czasami bez uzależnienia od konkretnych bibliotek, więc jestem zainteresowany, jak sam to wdrożyć. A więc, jak działa ten rodzaj rzeczy i jak zaimplementować go do wywołania funkcji?

+0

Metoda "wtedy" ma tendencję do bycia częścią "obietnicy". jQuery implementuje go jako część "odroczonego" api. – zzzzBov

+0

[douglas crockford krótko dotyka obietnic w swoim wykładzie "Monads and Gonads"] (http://www.youtube.com/watch?v=dkZFtimgAcM&t=1920) – zzzzBov

+0

Przeczytaj o propozycji obietnicy CommonJS, która zawiera również listę bibliotek możesz użyć: http://wiki.commonjs.org/wiki/Promises/A. –

Odpowiedz

4

Ten wzór nazywa się "obietnicami". Jego implementacja była między innymi przez jQuery i dojo, a jednym z nich byłoby przyjrzeć się ich kodowi i zobaczyć, jak go zaimplementować.

Ogólny wzór wdrożenia polega na utworzeniu funkcji, która zwraca obiekt, który zawiera funkcję (następnie), aby przekazać parę funkcji jako wywołania zwrotne poprzedniej metody, która następnie zostanie uruchomiona w przypadku sukcesu lub niepowodzenia. MSDN ma więcej o obietnicach w blog post here

Jest minimalistyczna realizacja wysłana na GitHub tutaj: Promises GIST

function Promise() { 
    this._thens = []; 
} 

Promise.prototype = { 

    /* This is the "front end" API. */ 

    // then(onResolve, onReject): Code waiting for this promise uses the 
    // then() method to be notified when the promise is complete. There 
    // are two completion callbacks: onReject and onResolve. A more 
    // robust promise implementation will also have an onProgress handler. 
    then: function (onResolve, onReject) { 
     // capture calls to then() 
     this._thens.push({ resolve: onResolve, reject: onReject }); 
    }, 

    // Some promise implementations also have a cancel() front end API that 
    // calls all of the onReject() callbacks (aka a "cancelable promise"). 
    // cancel: function (reason) {}, 

    /* This is the "back end" API. */ 

    // resolve(resolvedValue): The resolve() method is called when a promise 
    // is resolved (duh). The resolved value (if any) is passed by the resolver 
    // to this method. All waiting onResolve callbacks are called 
    // and any future ones are, too, each being passed the resolved value. 
    resolve: function (val) { this._complete('resolve', val); }, 

    // reject(exception): The reject() method is called when a promise cannot 
    // be resolved. Typically, you'd pass an exception as the single parameter, 
    // but any other argument, including none at all, is acceptable. 
    // All waiting and all future onReject callbacks are called when reject() 
    // is called and are passed the exception parameter. 
    reject: function (ex) { this._complete('reject', ex); }, 

    // Some promises may have a progress handler. The back end API to signal a 
    // progress "event" has a single parameter. The contents of this parameter 
    // could be just about anything and is specific to your implementation. 
    // progress: function (data) {}, 

    /* "Private" methods. */ 

    _complete: function (which, arg) { 
     // switch over to sync then() 
     this.then = which === 'resolve' ? 
      function (resolve, reject) { resolve(arg); } : 
      function (resolve, reject) { reject(arg); }; 
     // disallow multiple calls to resolve or reject 
     this.resolve = this.reject = 
      function() { throw new Error('Promise already completed.'); }; 
     // complete all waiting (async) then()s 
     var aThen, i = 0; 
     while (aThen = this._thens[i++]) { aThen[which] && aThen[which](arg); } 
     delete this._thens; 
    } 

}; 

(Zauważ, że to nie jest mój kod Spojrzałem przez to i dobrze wygląda jako punkt wyjścia. , ale cały kredyt trafia do original author)

Powiązane problemy