web-dev-qa-db-fra.com

Comment écrire des fonctions asynchrones pour Node.js

J'ai essayé de rechercher comment exactement les fonctions asynchrones devraient être écrites. Après beaucoup de recherches dans de nombreux documents, je ne comprends toujours pas.

Comment écrire des fonctions asynchrones pour Node? Comment dois-je implémenter correctement la gestion des événements d'erreur?

Une autre façon de poser ma question serait la suivante: comment interpréter la fonction suivante?

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

Aussi, j'ai trouvé cette question sur SO ("Comment créer une fonction asynchrone non bloquante dans node.js? ") intéressant. Je n'ai pas l'impression d'avoir reçu de réponse.

110
Kriem

Vous semblez confondre asynchrone IO avec des fonctions asynchrones. Node.js utilise une méthode asynchrone non bloquante IO car non bloquante IO = C’est mieux. La meilleure façon de le comprendre est d’aller regarder des vidéos de Ryan Dahl.

Comment écrire des fonctions asynchrones pour Node?

Il suffit d'écrire des fonctions normales, la seule différence est qu'elles ne sont pas exécutées immédiatement, mais transmises en tant que rappels.

Comment dois-je mettre en œuvre la gestion des événements d'erreur correctement

Généralement, les API vous rappellent avec une erreur comme premier argument. Par exemple

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

Est-ce un modèle commun.

Un autre motif commun est on('error'). Par exemple

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

Edit:

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

La fonction ci-dessus quand appelé comme

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

Imprimera 42 Sur la console de manière asynchrone. En particulier, process.nextTick Se déclenche une fois que la pile d'appels de la boucle d'événements en cours est vide. Cette pile d'appels est vide après l'exécution de async_function Et console.log(43). Nous imprimons donc 43 suivis de 42.

Vous devriez probablement lire un peu sur la boucle d'événement.

84
Raynos

Passer des rappels ne suffit pas. Vous devez utiliser settimer par exemple, pour rendre la fonction async.

Exemples: Fonctions non asynchrones:

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

Si vous allez exécuter l'exemple ci-dessus, cela devrait être bon, il faudra attendre jusqu'à ce que ces fonctions se terminent pour fonctionner.

Fonctions pseudo multithreads (asynchrones):

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

Celui-ci sera vraiment async. Cela devrait être bon sera écrit avant async fini.

9
calmbird

Vous devriez regarder ceci: Épisode 19 de Node Tuts - Modèles d'itérations asynchrones

Cela devrait répondre à vos questions.

5
Cris-O

Si vous SAVEZ qu'une fonction retourne une promesse, je suggère d'utiliser les nouvelles fonctionnalités async/wait en JavaScript. Cela donne à la syntaxe une apparence synchrone mais fonctionne de manière asynchrone. Lorsque vous ajoutez le mot-clé async à une fonction, il vous permet de await promettre dans cette étendue:

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

  console.log(r); // true
}

si une fonction ne retourne pas une promesse, je vous recommande de l'envelopper dans une nouvelle promesse que vous définissez, puis résolvez les données souhaitées:

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

En bout de ligne: tirer parti de la puissance des promesses.

3
ryanwaite28

Essayez ceci, cela fonctionne pour le noeud et le navigateur.

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

J'ai trop d'heures consacrées à une telle tâche pour node.js. Je suis principalement un gars front-end.

Je trouve cela assez important, car toutes les méthodes de noeud asyncroniennes traitent le rappel, et le transforment en promesse vaut mieux le gérer.

Je veux juste montrer un résultat possible, plus maigre et lisible. En utilisant ECMA-6 avec async, vous pouvez l'écrire comme ceci.

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

le (undefined || null) est pour les scénarios repl (lire la boucle d’impression d’événement), en utilisant également indéfini.

1
Yoarthur