2011-08-01 19 views
98

Próbowałem zbadać, jak dokładnie powinny być zapisane funkcje asynchroniczne. Po wielu przeorach dużej dokumentacji wciąż nie jestem pewien.Jak pisać funkcje asynchroniczne dla Node.js

Jak napisać funkcje asynchroniczne dla węzła? Jak poprawnie wdrożyć obsługę zdarzeń błędów?

Innym sposobem zadawania mojego pytania byłoby: Jak powinienem interpretować następującą funkcję?

var async_function = function(val, callback){ 
    process.nextTick(function(){ 
     callback(val); 
    }); 
}; 

Również znalazłem this question on SO („Jak mogę utworzyć nieblokujące asynchronicznego funkcji w node.js?”) Ciekawy. Nie mam ochoty na to jeszcze odpowiedzieć.

+13

Dlatego proszę. Nie jest dla mnie jasne, w jaki sposób te funkcje są inne. – Kriem

+0

Polecam, abyś spojrzał na 'setTimeout' i' setInterval' w swojej ulubionej przeglądarce i baw się z nimi również. Lub wywołania ajaxowe (prawdopodobnie najbardziej zbliżone do doświadczenia węzła) lub detektory zdarzeń dla rzeczy, które znasz, takich jak zdarzenia klikania i ładowania. Model asynchroniczny istnieje już w przeglądarce i jest dokładnie taki sam w węźle. – davin

+0

@davin - Chyba nie w pełni rozumiem wtedy model asynchroniczny. – Kriem

Odpowiedz

77

Wygląda na to, że wprowadzasz w błąd asynchroniczne IO z funkcjami asynchronicznymi. node.js używa asynchronicznego nieblokującego IO, ponieważ nie blokujące IO jest lepsze. Najlepszym sposobem, aby to zrozumieć, jest obejrzenie filmów Ryana Dahla.

Jak napisać funkcje asynchroniczne dla węzła?

Po prostu pisz normalne funkcje, jedyną różnicą jest to, że nie są wykonywane natychmiast, ale przekazywane jako wywołania zwrotne.

Jak należy wdrożyć zdarzenie błędu obsługi prawidłowo

Ogólnie API daje zwrotnego z ERR jako pierwszy argument. Na przykład:

database.query('something', function(err, result) { 
    if (err) handle(err); 
    doSomething(result); 
}); 

Jest to wspólny wzór.

Innym częstym wzorem jest on('error'). Na przykład

process.on('uncaughtException', function (err) { 
    console.log('Caught exception: ' + err); 
}); 

Edit:

var async_function = function(val, callback){ 
    process.nextTick(function(){ 
     callback(val); 
    }); 
}; 

Powyższa funkcja, gdy nazywa się

async_function(42, function(val) { 
    console.log(val) 
}); 
console.log(43); 

wypisze 42 do konsoli asynchronicznie. W szczególności process.nextTick strzela po tym, jak bieżący pakiet zdarzeń eventloop jest pusty. Ten stos wywołań jest pusty po uruchomieniu async_function i console.log(43). Więc drukujemy 43, a następnie 42

Prawdopodobnie powinieneś zrobić trochę czytania w pętli zdarzeń.

+0

Widziałem filmy z Dahl, ale wydaje mi się, że nie rozumiem sprawy, której się boję. :( – Kriem

+1

@Kriem zobacz zaktualizowaną odpowiedź i przeczytaj [o pętli wydarzenia] (http://en.wikipedia.org/wiki/Event_loop) – Raynos

+1

Dzięki temu wglądom jestem teraz bardziej świadomy tego, czego mi brakuje. :) Twój ostatni przykład pomógł przy okazji. – Kriem

2

Spróbuj tego, działa zarówno dla węzła, jak i przeglądarki.

isNode = (typeof exports !== 'undefined') && 
(typeof module !== 'undefined') && 
(typeof module.exports !== 'undefined') && 
(typeof navigator === 'undefined' || typeof navigator.appName === 'undefined') ? true : false, 
asyncIt = (isNode ? function (func) { 
    process.nextTick(function() { 
    func(); 
    }); 
} : function (func) { 
    setTimeout(func, 5); 
}); 
+16

4 downvotes i nawet jeden konstruktywny komentarz ..: \ – Omer

+6

@Omer Takie jest życie na SO. –

+0

@Omer kodu jest zrozumiały dla ciebie –

6

Przekazywanie połączeń zwrotnych nie wystarczy. Musisz na przykład użyć settimer, aby funkcja asynchroniczna.

Przykłady: Nie asynchroniczny funkcje:

function a() { 
    var a = 0;  
    for(i=0; i<10000000; i++) { 
    a++; 
    }; 
    b(); 
}; 

function b() { 
    var a = 0;  
    for(i=0; i<10000000; i++) { 
    a++; 
    };  
    c(); 
}; 

function c() { 
    for(i=0; i<10000000; i++) { 
    }; 
    console.log("async finished!"); 
}; 

a(); 
console.log("This should be good"); 

Jeśli trafisz powyżej przykład, powinno być dobrze, będą musieli poczekać aż zakończy te funkcje do pracy.

pseudo wielowątkowy (asynchroniczny) funkcje:

function a() { 
    setTimeout (function() { 
    var a = 0; 
    for(i=0; i<10000000; i++) { 
     a++; 
    }; 
    b(); 
    }, 0); 
}; 

function b() { 
    setTimeout (function() { 
    var a = 0; 
    for(i=0; i<10000000; i++) { 
     a++; 
    }; 
    c(); 
    }, 0); 
}; 

function c() { 
    setTimeout (function() { 
    for(i=0; i<10000000; i++) { 
    }; 
    console.log("async finished!"); 
    }, 0); 
}; 

a(); 
console.log("This should be good"); 

Ten będzie trully asynchroniczny. To powinno być dobre, zostanie napisane przed zakończeniem asynchronicznego.

0

Jeśli wiesz, że funkcja zwraca obietnicę, sugeruję użycie nowych funkcji asynchronicznych/oczekujących w JavaScript. Sprawia, że ​​składnia wygląda synchronicznie, ale działa asynchronicznie. Po dodaniu słowa kluczowego async do funkcji, pozwala na await obietnic w tym zakresie:

async function ace() { 
    var r = await new Promise((resolve, reject) => { 
    resolve(true) 
    }); 

    console.log(r); // true 
} 

jeśli funkcja nie zwraca obietnicę, polecam owinięcie go w nowym obietnicy, że można zdefiniować, a następnie rozwiązać dane, które chcesz:

function ajax_call(url, method) { 
    return new Promise((resolve, reject) => { 
    fetch(url, { method }) 
    .then(resp => resp.json()) 
    .then(json => { resolve(json); }) 
    }); 
} 

async function your_function() { 
    var json = await ajax_call('www.api-example.com/some_data', 'GET'); 
    console.log(json); // { status: 200, data: ... } 
} 

Podsumowanie: wykorzystaj moc obietnic.

Powiązane problemy