web-dev-qa-db-fra.com

Pourquoi les noms de variables en attente et asynchrones sont-ils valides?

J'expérimentais comment / est interprété autour de différents mots clés et opérateurs, et a constaté que la syntaxe suivante est parfaitement légale:

// awaiting something that isn't a Promise is fine, it's just strange to do:
const foo = await /barbaz/
myFn()

Erreur:

Uncaught ReferenceError: l'attente n'est pas définie

On dirait qu'il essaie d'analyser le await comme nom de variable ..? je m'attendais à

attendre n'est valable que dans la fonction asynchrone

ou peut-être quelque chose comme

Un jeton inattendu vous attend

À mon horreur, vous pouvez même lui attribuer des choses:

const await = 'Wait, this actually works?';
console.log(await);

Quelque chose d'aussi manifestement erroné ne devrait-il pas provoquer une erreur de syntaxe, comme c'est le cas pour let, finally, break, etc.? Pourquoi est-ce autorisé et que diable se passe-t-il dans le premier extrait?

39

Les mots-clés réservés ne peuvent pas être utilisés comme identifiants (noms de variables) . Contrairement à la plupart des autres mots Javascript spéciaux (comme ceux répertoriés dans la question, let, finally, ...), await est pas un mot clé réservé, donc son utilisation comme nom de variable ne renvoie pas de SyntaxError. Pourquoi n'a-t-il pas été transformé en mot clé réservé lorsque la nouvelle syntaxe est sortie?

Rétrocompatibilité

En 2011, alors qu'ES5 était encore relativement nouveau, le code qui utilisait await (et async) comme noms de variable était parfaitement valide, donc vous avez peut-être vu quelque chose comme ça sur quelques sites :

function timeout(ms) {
  var await = $.Deferred();
  setTimeout(await.resolve, ms);
  return await.promise();
};

Le choix de ce nom de variable peut sembler étrange, mais il n'y avait rien mauvais avec lui. await et async n'ont jamais été des mots clés réservés - si les rédacteurs de la spécification ES2017 ont transformé await en mot clé réservé et que les navigateurs ont mis en œuvre ce changement, les personnes visitant ces anciens sites sur les nouveaux navigateurs ne pourraient pas utiliser ces sites; ils seraient probablement cassés.

Donc, peut-être que s'ils étaient transformés en mots clés réservés, un peu sites qui ont choisi un nom de variable particulier ne fonctionneraient pas correctement - pourquoi l'existence de ces sites affecterait-elle en permanence l'évolution future d'ECMAscript et du résultat en confondant le code comme dans la question?

Parce que les navigateurs refuseront d'implémenter une fonctionnalité qui casse les sites existants. Si un utilisateur constate qu'un site ne fonctionne pas sur un navigateur, mais fonctionne sur un autre, cela les incitera à changer les navigateurs - le fabricant du premier navigateur n'en voudrait pas, car cela signifierait pour eux moins de parts de marché, même si c'est une fonctionnalité qui rend la langue plus cohérente et compréhensible. De plus, les éditeurs de la spécification ne veulent pas ajouter quelque chose qui ne sera jamais implémenté (ou ne sera implémenté que sporadiquement), car alors la spécification perdrait une partie de son statut de norme - contrairement à son objectif principal.

Vous pouvez voir ces interactions en action avec Array.prototype.flatten et Array.prototype.contains - lorsque les navigateurs ont commencé à les expédier, il a été constaté qu'ils cassaient quelques sites existants en raison de conflits de noms, de sorte que les navigateurs se sont retirés de l'implémentation, et la spécification a dû être modifiée (les méthodes ont été renommées en - .flat et .includes ).


Il y a en fait est une situation dans laquelle await ne peut pas être utilisé comme identifiant, qui est à l'intérieur des modules ES6:

<script type="module">
  const await = 'Does it work?';
</script>

En effet, pendant que les modules ES6 (ES2015) étaient en cours de calcul, async/await était déjà à l'horizon ( commit initial pour le async/await proposition peut être vu au début de 2014), donc lors de la conception des modules, await pourrait devenir un mot-clé réservé pour préparer l'avenir, sans casser aucun site existant.


En ce qui concerne le premier extrait de la question:

const foo = await /barbaz/
myFn()

Ceci est syntaxiquement valide car await est un nom de variable valide en dehors des fonctions async, et l'interprète pense que vous essayez de diviser, plutôt que d'utiliser un expression régulière:

const foo = await / barbaz / myFn()

Ne pas compter sur l'insertion automatique de points-virgules aurait identifié le problème plus tôt, car le dernier / ne pouvait pas être interprété comme une division:

const foo = await /barbaz/;
myFn();

Cette situation quelque peu ambiguë a été spécifiquement évoquée lors d'un réunion TC39 le async/await:

YK: De quoi vous inquiétez-vous?

WH: Ambiguïtés sur les séquences de code qui commencent par attendent/et sont ensuite interprétées de manière divergente (en raison de la distinction attente-comme-identificateur vs attente-comme-opérateur qui inverse le/entre la division et le début d'une expression rationnelle) par les grammaires de couverture par rapport aux grammaires réelles. C'est une ferme de bogues potentielle.

66