Est-ce qu'une API async devrait lancer en même temps?

j'écris une fonction JavaScript qui fait une requête HTTP et renvoie une promesse pour le résultat (mais cette question s'applique également pour une implémentation basée sur la callback).

si je sais immédiatement que les arguments fournis pour la fonction sont invalides, la fonction throw doit-elle être synchronisée, ou doit-elle retourner une promesse rejetée (ou, si vous préférez, invoquer la fonction callback avec une instance Error )?

comme c'est important qu'une fonction async devrait toujours se comporter d'une manière async, en particulier pour les conditions d'erreur? Est-il OK pour throw si vous savez que le programme n'est pas dans un état convenable pour l'opération asynchrone procéder?

E. g:

function getUserById(userId, cb) {
  if (userId !== parseInt(userId)) {
    throw new Error('userId is not valid')
  }

  // make async call
}

// OR...

function getUserById(userId, cb) {
  if (userId !== parseInt(userId)) {
    return cb(new Error('userId is not valid'))
  }

  // make async call
}
6
demandé sur Bergi 2014-02-19 21:27:10

3 réponses

en fin de compte la décision de lancer ou non de façon synchrone est à vous, et vous trouverez probablement des gens qui argumentent de chaque côté. La chose importante est de documenter le comportement et de maintenir la cohérence dans le comportement.

Mon avis sur la question est que votre deuxième option de passage de l'erreur dans la fonction de rappel semble plus élégant. Sinon, vous finissez avec un code qui ressemble à ceci:

try {
    getUserById(7, function (response) {
       if (response.isSuccess) {
           //Success case
       } else {
           //Failure case
       }
    });
} catch (error) {
    //Other failure case
}

la commande flux ici est un peu déroutant.

il semble qu'il serait préférable d'avoir une structure unique if / else if / else dans le rappel et de renoncer à l'environnement try / catch .

6
répondu Timothy Shields 2014-02-19 17:36:57

dans quelle mesure est-il important qu'une fonction asynchrone se comporte toujours de manière asynchrone, en particulier dans des conditions d'erreur?

très important .

Est-il OK pour throw si vous savez que le programme n'est pas dans un état convenable pour l'opération asynchrone procéder?

Oui, je pense personnellement que c'est OK quand il s'agit d'une erreur très différente de celles produites de façon asynchrone et qui doit être traitée séparément de toute façon.

si certains userids sont connus pour être invalides parce qu'ils ne sont pas numériques, et certains sont seront rejetés sur le serveur (par exemple parce qu'ils sont déjà pris), vous devez systématiquement faire un (async!) la fonction de rappel pour les deux cas. Si les erreurs async ne sont dues qu'à des problèmes de réseau, etc., vous pouvez les signaler différemment.

vous pouvez toujours throw lorsqu'une " inattendu " erreur se produit. Si vous demande valide identifiants, vous pourriez jeter sur les invalides. Si vous voulez anticiper les non valides et vous attendre à ce que l'appelant les gère, vous devez utiliser une route d'erreur "unifiée" qui serait la promesse de rappel/rejeté pour une fonction async.

et pour répéter @Timothy: vous devez toujours documenter le comportement et maintenir la cohérence dans le comportement.

2
répondu Bergi 2014-02-19 20:20:23

Callback APIs idéalement ne devrait pas lancer, mais ils le font parce que c'est très difficile à éviter puisque vous devez avoir essayer de attraper littéralement partout. Rappelez-vous que l'erreur de lancer explicitement par throw n'est pas requise pour une fonction à lancer. Une autre chose qui ajoute à cela est que le rappel de l'utilisateur peut facilement lancer trop, par exemple en appelant JSON.parse sans try catch.

voilà à quoi ressemblerait le code qui se comporte selon ces idéaux:

readFile("file.json", function(err, val) {
    if (err) {
        console.error("unable to read file");
    }
    else {
        try {
            val = JSON.parse(val);
            console.log(val.success);
        }
        catch(e) {
            console.error("invalid json in file");
        }
    }
});

avoir à utiliser 2 mécanismes différents de gestion des erreurs est vraiment incommode, donc si vous ne voulez pas que votre programme soit un fragile château de cartes (en n'écrivant aucun try catch jamais) , vous devriez utiliser des promesses qui unifient toutes la gestion des exceptions sous un seul mécanisme:

readFile("file.json").then(JSON.parse).then(function(val) {
    console.log(val.success);
})
.catch(SyntaxError, function(e) {
    console.error("invalid json in file");
})
.catch(function(e){
    console.error("unable to read file")
})
1
répondu Esailija 2014-02-20 06:29:34