2015-01-16 23 views
7

Jestem dość nowy w JavaScript i pracuję w węźle, który wymaga dobrego zrozumienia programowania asynchronicznego i projektowania wywołań zwrotnych. Odkryłem, że korzystanie z funkcji osadzonych jest bardzo łatwe, nawet gdy połączenia zwrotne mają wiele poziomów. Wbudowane callbacki kończą się zamknięciami.Jak zaimplementować funkcje wywołania zwrotnego wielokrotnego użytku

Jednak, gdy masz kilka warstw wywołań zwrotnych, w których wiele wywołań zwrotnych jest podobnych w różnych trasach wykonania, możesz wielokrotnie przepisywać wiele kodów zwrotnych w osobnych łańcuchach wywołań zwrotnych. Na przykład, jeśli definicje mycb1 i mykb2 poniżej zostaną przeniesione poza A, nie będą one już miały niejawnego dostępu do zmiennych A, a zatem przestaną funkcjonować jako zamknięcia.

Przykład z definicjami osadzonymi, w których działają one jako zamknięcia.

mod.A=function(){ 
    var mycb1=function(err){ 
    if (!err){ 
     var mycb2=function(err){ 
     cb(err); 
     }; 
     mod.foo2(args,mycb2); 
    } 
    else{cb(err);} 
    }; 
    mod.foo1(args,mycb1); 
} 

mod.foo1 = function(args,cb){ 
    //do some work 
    cb(err); 
}; 

mod.foo2 = function(args,cb){ 
    //do some work 
    cb(err); 
} 
//execute 
mod.A(); 

Chcę wykonać następujące czynności, ale można zmienić zakres zmienny funkcji mycb1 i mycb2 więc mogą być stosowane jako zamknięcia skąd kiedykolwiek są one nazywane. Na przykład:

var mycb2=function(err){ 
    ... 
    cb(err); 
}; 

var mycb1=function(err){ 
    if (!err){   
    mod.foo2(args,mycb2); //but have it act like a closure to mycb1 
    } 
    else{cb(err);} 
}; 

mod.A=function(){ 
    ... 
    mod.foo1(args,mycb1); //but have it act like a closure to A 
} 

mod.foo1 = function(args,cb){ 
    //do some work 
    cb(err); 
} 

mod.foo2 = function(args,cb){ 
    //do some work 
    cb(err); 
} 

wiem, że mogę realizować projekt, który ustawia zmienną zarówno na poziomie mod więc są one dostępne dla funkcji poziom modyfikacji. Wydaje się to jednak w pewien sposób zanieczyszczać zakres modowy zmienną, z której mogą korzystać tylko niektóre z jego metod. Wiem również, że mogę przekazywać zmienne, aby były one dostępne dla wywołań zwrotnych, gdy są wykonywane. Jednakże, jeśli rozumiem, jak działają JS i wywołania zwrotne, będę musiał je przekazać do fooX, a następnie foo przekazać je do wywołań zwrotnych. To też nie wygląda na dobry plan. Czy zmienny zakres funkcji może zostać zmieniony, aby działał jak zamknięcie z punktu realizacji, a nie z punktu widzenia definicji? Jeśli nie, jaki jest najlepszy sposób na modularyzację kodu wywołania zwrotnego, aby można go było ponownie wykorzystać?

+1

można użyć funkcji Function.bind() do cementowania znanych wartości w nazwane wywołania zwrotne w czasie wykonywania. to jest prawie tak blisko "zamknięcia z punktu jego realizacji", jak to się stanie, jeśli dobrze cię zrozumiem. – dandavis

+0

można również używać obietnic do utrzymywania stanu bez zamykania modułów nadmiernie przepełnionych. – dandavis

+0

Doskonała porada. Dziękuję Ci. – rss181919

Odpowiedz

6

Ogólnie rzecz biorąc, nie ma konieczności poruszania się w celu utworzenia innej funkcji, która ma dostęp do zamknięć. Możesz utworzyć funkcję in-line, mając prostą funkcję anonimową, która przekazuje pewne argumenty do nadrzędnego wywołania zwrotnego jako parametry podczas akceptowania reszty (tj. Funkcję częściową) lub używając Function.bind() do utworzenia samej funkcji częściowej.

Na przykład, jeśli początkowo miał:

function(...) { 
    // closure vars x1, y1 
    foo.bar(function(result) { 
     // do something with x1 and y1 
    }); 
} 

Można wyodrębnić, że aby:

var callback = function(x1, y1, result) { 
    // do something with x1 and y1 
}; 

function(...) { 
    // closure vars x1, y1 

    // option 1: make your own partial function 
    foo.bar(function(result) { return callback(x1, y1, result); }); 
    // with ES6: foo.bar((result) => callback(x1, y1, result); }); 

    // option 2: use Function.bind 
    foo.bar(callback.bind(this, x1, y1);); 
} 
+0

To jest to, czego potrzebowałem. Dzięki za opracowanie odpowiedzi. To naprawdę pomaga nowicjuszowi :) – rss181919

1

tutaj jest zagnieżdżona przykład zwrotna bez zamknięcia i bez zagnieżdżania. przechwytuje wskazaną stronę, znajduje trzeci link, a następnie pokazuje źródło tego łącza do użytkownika.

w tym przypadku, po uruchomieniu z tego miejsca w konsoli i podaniu strony głównej, strona wylogowania jest trzecim linkiem, a jego zawartość jest powiadamiana.

wszystkie wywołania zwrotne są rodzeństwem, a nie istnieją żadne zewnętrzne zmienne stanu, po prostu czysty asynchroniczny funkcjonalny:

// look ma, no nesting! 
function ajax(a, c) { 
    var e = new XMLHttpRequest; 
    e.onload= ajaxOnload.bind(this, c, e); 
    e.open("GET", a, !0); 
    e.send(); 
    return e 
} 

function ajaxOnload(c, e) { 
    c(e.responseText, e); 
} 

function cbFind3(cb, s){ 
    var t=document.createElement("body"); 
    t.innerHTML=s; 
    var lnk= t.getElementsByTagName("a")[3].href; 
    ajax(lnk, cb);  
} 

function grabThirdLinkSource(url, cb){ 
    ajax(url, cbFind3.bind(this, cb)); 
} 

grabThirdLinkSource("/", alert); 

to nie jest najbardziej użytecznym przykładem, ale nie pokazuje jak funkcje łańcuch w poprzek inwokacji z bind (). Użyłem vanilla ajax i uniknąłem obietnic, aby pokazać, jak ten styl interakcji działa bez żadnych komplikacji. nawet helper ajax używa funkcji bez zagnieżdżania, aby przekazać responseText do callbacków "core" zamiast zdarzenia lub całego obiektu xhr.

+0

Dzięki. Twój przykład pomaga potwierdzić to, co sugerowali dwaj poprzedni użytkownicy. Prawda jest taka, że ​​chciałem wymusić wykonywanie wywołań zwrotnych z tym samym zakresem zmiennych, w którym wykonywany był kod wywołujący, a nie można tego zrobić w javascript. Możesz użyć funkcji częściowych lub powiązania, aby wymusić zasięg obiektu, ale dostęp zmienny można osiągnąć tylko poprzez przekazywanie argumentów do parametrów funkcji. – rss181919

+0

możesz zadzwonić z zakresu leksykalnego do wywoływania funkcji przez _eval_ lub _with_, ale podejście funkcjonalne używające przekazywania argumentów zwykle działa lepiej na dłuższą metę i zapewnia wydajność, wymuszając przynajmniej częściowe hermetyzowanie, ponowne zastosowanie i wbudowane "zarządzanie pamięcią ". Z początku wydaje się nieco inny i tak jest, ale ten styl kontynuacji działa bardzo dobrze dla zależnych/powiązanych procesów asynchronicznych. – dandavis

Powiązane problemy