2013-07-09 11 views
6

Jestem trochę w stanie nauczyć się javascript i mam pytanie dotyczące łączenia połączeń synchronicznych i asynchronicznych z funkcjami. To będzie tylko teoretyczny problem, ale mam nadzieję, że przekazuje ten pomysł.Jak łączyć połączenia asynchroniczne z synchronicznymi w javascript

Załóżmy, że mamy program javascript, który decyduje, ile bananów i pomarańczy muszę kupić.

console.log('buy %d bananas and %d oranges', bananas, oranges) 

Teraz mogę zdecydować ile banany można kupić, ale muszę zapytać moją żonę, ile pomarańcze chce, więc jej tekst. (Mogę napisać funkcję asynchroniczną, aby to przedstawić).

Byłby to mój bezpośredni dojazd:

var bananas = 10; 
var oranges = 0; 
textWife('askAboutOranges',function(number){ oranges = number; } 
console.log('buy %d bananas and %d oranges', bananas, oranges) 

Ale dla mnie to nie ma sensu, bo trzeba czekać na moja żona odpowiedzieć, więc prawdopodobnie nie będzie miał liczbę pomarańczy o czasie.

Więc mogę zmienić mój program:

var bananas = 10; 
var oranges = 0; 
textWife('askAboutOranges',function(number){ 
    oranges = number; 
    console.log('buy %d bananas and %d oranges', bananas, oranges); 
} 

Ale nie podoba mi się to, bo teraz mam logikę podejmowaniu decyzji co do zakupu w tym banany, wewnątrz odpowiedzi od mojej żony. Co jeśli zdecyduję Nie chcę pomarańcze, muszę zrobić coś takiego:

var bananas = 10; 
var oranges = 0; 
if (wantOranges) 
{ 
    textWife('askAboutOranges',function(number){ 
    oranges = number; 
    console.log('buy %d bananas and %d oranges', bananas, oranges); 
    } 
} 
else 
    console.log('buy %d bananas and %d oranges', bananas, oranges); 

Więc moje pytanie brzmi: Czy ktoś może mi wyjaśnić, co jest najlepszym/prawy sposób zrobić coś takiego?

Odpowiedz

7

jQuery Deferred jest doskonałym narzędziem mieć w swoim pasem. Mogę zrobić coś podobnego do oddzielnych obawy:

function decideHowManyBananas() { 
    return 10; 
} 

function decideHowManyOranges() { 
    var deferred = $.Deferred(); 

    if (wantOranges) { 
     textWife('askAboutOranges', function(number) { 
      deferred.resolve(number); 
     }); 
    } else { 
     deferred.resolve(0); 
    } 

    return deferred.promise(); 
} 

$.when(decideHowManyBananas(), decideHowManyOranges()).done(function(bananas, oranges) { 
    console.log('buy %d bananas and %d oranges', bananas, oranges); 
}); 
+0

Myślę, że to jest to, co chciałem, po prostu myślałem, że jest coś w macierzystym javascript, aby sobie z tym poradzić. –

0

Przygotuj funkcję i używać go w obu przypadkach usunąć powielania kodu:

var bananas = 10; 
var oranges = 0; 
function buyStuff() { 
    console.log('buy %d bananas and %d oranges', bananas, oranges); 
} 
if (wantOranges) 
    textWife('askAboutOranges',function(number){ 
    oranges = number; 
    buyStuff(); 
    }) 
else 
    buyStuff(); 
+0

Dodanie nowej funkcji do zawijania istniejącego wywołania funkcji nie poprawia wydajności ani czytelności oryginalnego kodu. –

+0

@RobRaisch - tak, robi. Metoda 'buyStuff' jest koncepcyjnie w domenie problemowej" rzeczy, które powinien wykonywać mój program ". 'console.log' to specyficzne wywołanie komponentu przeglądarki, który nie ma nic wspólnego z celami aplikacji. – Dancrumb

+0

Ponadto, trywialne przykłady często wydają się wskazywać, że podejście jest nieskuteczne, ale w rzeczywistości niewiele mówią o tym, jak efektywność rozwiązania skaluje się i gdzie są prawdziwe kompromisy. Minuta 'buyStuff' staje się większa, zaczniesz widzieć wypłatę w wydajności rozwoju. – Dancrumb

0

w pierwszym przykładzie, należy stwierdzić, że odpowiedź na pytanie: „Ilu banany i pomarańcze mam kupić?” jest zależna od posiadanych przez Ciebie informacji, tj. liczby potrzebnych bananów, a także informacji, których nie posiadasz, liczby potrzebnych pomarańczy, więc nie możesz na nie odpowiedzieć bez uprzedniego uzyskania brakujących informacji.

Następnie zmieniasz kod, aby odłożyć odpowiedź na swoje pytanie, dopóki nie uzyskasz brakujących informacji, co jest typowym podejściem do rozwiązania tego rodzaju zależności.

Następnie oświadczasz, że to Cię nie zadowala, ponieważ nie możesz w ogóle kupić pomarańczy. Jest to nowy wymóg i dlatego unieważnia twoje pierwotne pytanie, zmieniając je na "ile bananów mam kupić?"

Usuwając wymóg brakujących informacji, zmieniasz pytanie, a więc musisz rozwiązać specjalny problem na dwa pytania.

Ostatnim przykładem podać kod robi to pierwszy podjęciem decyzji, czy należy zakupić zarówno banany i pomarańcze lub zaledwie pomarańczy, który jest rzeczywiście najprostszym sposobem rozwiązania tego problemu.

3

Nie ma najlepszego/najlepszego sposobu - zawsze zależy. Nowoczesne biblioteki JavaScript używają takich pojęć, jak Odroczenia i obietnice, aby zsynchronizować wiele połączeń asynchronicznych, połączeń synchronizacyjnych i natychmiastowych danych.JQuery, kod może być zapisany jako:

$.when({bananas:10, oranges:1}, textWife('askAboutOranges')).done(function(myList, herList) { 
    buyBananas(myList.bananas); 
    buyOranges(myList.oranges + herList.oranges); 
}); 

Zobacz http://api.jquery.com/category/deferred-object/ aby uzyskać więcej informacji.

I to jest sposób tworzenia odroczonego obiektów w kodzie, w elegancki sposób:

function decideHowManyOranges() { 
    if (!wantOranges) 
     return 0; 
    return $.Deferred(function(d) { 
     textWife('askAboutOranges', function(number) { 
      d.resolve(number); 
     }) 
    }) 
} 

numOfBananas = 10 

$.when(numOfBananas, decideHowManyOranges()).done(function(bananas, oranges) { 
    console.log('buy %d bananas and %d oranges', bananas, oranges); 
}); 
1

obietnicami

// setup 
var bananas = 4 
var wantOranges = true 
function textWife() { return new Promise((resolve, reject) => setTimeout(() => resolve(8), 1000)) } 

// execution 
Promise.all([ 
    bananas, 
    wantOranges ? textWife() : 0 // ternary is necessary here because boolean logs as `NaN` 
]).then(([bananas, oranges]) => console.log('buy %d bananas and %d oranges', bananas, oranges)) 

Uwaga: używam ..
Promises
Destructuring assignment gdzie var [bananas, oranges] = [4, 8] jest taka sama jak var bananas = 4, oranges = 8.
Arrow functions() => {}

Powiązane problemy