Come scrivere funzioni asincrone per Node.js


114

Ho provato a ricercare come scrivere esattamente le funzioni asincrone. Dopo aver esaminato un sacco di documentazione, non mi è ancora chiaro.

Come si scrivono funzioni asincrone per Node? Come devo implementare correttamente la gestione degli eventi di errore?

Un altro modo per porre la mia domanda sarebbe questo: come devo interpretare la seguente funzione?

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

Inoltre, ho trovato interessante questa domanda su SO ("Come creo una funzione asincrona non bloccante in node.js?"). Non mi sembra che abbia ancora ricevuto una risposta.


14
Ecco perché te lo chiedo. Non mi è chiaro come queste funzioni siano diverse.
Kriem

Ti consiglio di guardare setTimeoute setIntervalnel tuo browser preferito e di giocare anche con loro. O callback ajax (probabilmente la cosa più vicina all'esperienza del nodo) o listener di eventi per cose che conosci come fare clic e caricare eventi. Il modello asincrono esiste già nel browser e sono esattamente gli stessi in node.
davin

@davin - Immagino di non comprendere appieno il modello asincrono allora.
Kriem

@ Kriem, ieri ho risposto a qualcosa che potrebbe aiutare: stackoverflow.com/questions/6883648/… Non è una risposta alla tua domanda, ma è in tema. Prova a leggere la domanda e rispondi lì e gioca con il codice per cercare di capire cosa sta succedendo.
davin

2
@ Raynos Qual è la definizione di "funzione asincrona"?
Anderson Green

Risposte:


85

Sembra che tu stia confondendo l'IO asincrono con le funzioni asincrone. node.js utilizza l'IO non bloccante asincrono perché l'IO non bloccante è migliore. Il modo migliore per capirlo è guardare alcuni video di ryan dahl.

Come si scrivono funzioni asincrone per Node?

Basta scrivere normali funzioni, l'unica differenza è che non vengono eseguite immediatamente ma passate come callback.

Come devo implementare correttamente la gestione degli eventi di errore

Generalmente le API ti danno un callback con un errore come primo argomento. Per esempio

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

È un modello comune.

Un altro modello comune è on('error'). Per esempio

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

Modificare:

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

La funzione di cui sopra quando viene chiamata come

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

Verrà stampato 42sulla console in modo asincrono. In particolare process.nextTicksi attiva dopo che il callstack di eventloop corrente è vuoto. Quello stack di chiamate è vuoto dopo async_functione console.log(43)sono stati eseguiti. Quindi stampiamo 43 seguito da 42.

Probabilmente dovresti leggere un po 'sul ciclo degli eventi.


Ho visto i video di Dahl, ma non mi sembra di capire la questione, temo. :(
Kriem

1
@Kriem guarda la risposta aggiornata e leggi il loop degli eventi
Raynos

1
Grazie per gli approfondimenti. Ora sono più consapevole di ciò che mi manca nella conoscenza. :) Il tuo ultimo esempio ha aiutato a proposito.
Kriem

Penso che la tua dichiarazione sull'IO asincrono sia "migliore" sia troppo generica. In questo senso sì, ma nel complesso potrebbe non essere così.
Jake B

Nel tuo primo esempio di codice, controlli l'argomento err, ma non sei tornato in seguito. In caso di errore, il codice continuerà e potrebbe causare seri problemi nell'applicazione.
Gabriel McAdams

9

Il solo passaggio di callback non è sufficiente. Devi usare settimer per esempio, per rendere la funzione asincrona.

Esempi: funzioni non asincrone:

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

Se eseguirai l'esempio sopra, questo dovrebbe essere buono, dovrai aspettare fino a quando quelle funzioni finiranno di funzionare.

Funzioni pseudo multithread (asincrone):

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

Questo sarà veramente asincrono. Questo dovrebbe essere buono verrà scritto prima del termine dell'asincronia.



3

Se SAPETE che una funzione restituisce una promessa, suggerisco di utilizzare le nuove funzionalità async / await in JavaScript. Rende la sintassi sincrona ma funziona in modo asincrono. Quando aggiungi la asyncparola chiave a una funzione, ti consente di fare awaitpromesse in tale ambito:

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

  console.log(r); // true
}

se una funzione non restituisce una promessa, ti consiglio di racchiuderla in una nuova promessa che definisci, quindi risolvi i dati che desideri:

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: ... }
}

Conclusione: sfruttare il potere delle promesse.


La cosa da ricordare qui è che il corpo della promessa viene ancora eseguito in modo sincrono.
shadow0359

2

Prova questo, funziona sia per il nodo che per il browser.

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

18
4 voti negativi e nemmeno un commento costruttivo ..: \
Omer

6
@Omer Tale è la vita su SO.
Pezzo digitale

6
@NorbertoBezi Forse il codice è autoesplicativo per te, ma non per colui che ha pubblicato la risposta. Ecco perché è sempre una buona pratica spiegare al momento del downvoting.
Omer

0

Ho occupato troppe ore per questo compito in node.js. Sono principalmente un ragazzo front-end.

Lo trovo abbastanza importante, perché tutti i metodi dei nodi asincroni si occupano di callback e trasformarlo in Promise è meglio gestirlo.

Voglio solo mostrare un possibile risultato, più snello e leggibile. Usando ECMA-6 con async puoi scriverlo in questo modo.

 async function getNameFiles (dirname) {
  return new Promise((resolve, reject) => {
    fs.readdir(dirname, (err, filenames) => {
      err !== (undefined || null) ? reject(err) : resolve(filenames)
    })
  })
}

la (undefined || null)è per Repl scenari (lettura evento ciclo di stampa), usando il lavoro non definito anche.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.