


Introduction détaillée aux exemples de code de l'historique d'évolution asynchrone JavaScript
Préface
La méthode d'appel asynchrone la plus basique dans JS est le rappel, qui transmet la fonction de rappel à l'API asynchrone, et le navigateur ou le nœud informe le moteur JS après l'appel asynchrone. achèvement Rappel d'appel. Pour les opérations asynchrones simples, il suffit d'utiliser le rappel. Mais avec l’émergence des pages interactives et de Node, les inconvénients de la solution de rappel ont commencé à apparaître. La spécification Promise est née et intégrée à la spécification ES6. Plus tard, ES7 a incorporé des fonctions asynchrones dans la norme basée sur Promise. C'est l'histoire de l'évolution asynchrone de JavaScript.
Synchronisation et asynchrone
Habituellement, le code est exécuté de haut en bas. S'il y a plusieurs tâches, elles doivent être mises en file d'attente. La tâche précédente sera terminée avant que la tâche suivante ne soit exécutée. Ce mode d'exécution est dit synchrone. Les novices peuvent facilement confondre synchronisation en langage informatique et synchronisation en langage courant. Par exemple, la synchronisation dans « synchroniser les fichiers avec le cloud » fait référence à « garder... la cohérence ». Sur les ordinateurs, la synchronisation fait référence au mode dans lequel les tâches sont exécutées séquentiellement de haut en bas. Par exemple :
A(); B(); C();
Dans ce code, A, B et C sont trois fonctions différentes, et chaque fonction est une tâche indépendante. En mode synchrone, l'ordinateur effectuera la tâche A, puis la tâche B et enfin la tâche C. Dans la plupart des cas, le mode synchronisation convient. Mais si la tâche B est une requête réseau de longue durée et que la tâche C affiche une nouvelle page, la page Web se bloquera.
Une meilleure solution consiste à diviser la tâche B en deux parties. Une partie exécute immédiatement les tâches demandées par le réseau et l'autre partie exécute les tâches après le retour de la demande. Ce modèle dans lequel une partie est exécutée immédiatement et l’autre partie est exécutée dans le futur est appelé asynchrone.
A(); // 在现在发送请求 ajax('url1',function B() { // 在未来某个时刻执行 }) C(); // 执行顺序 A => C => B
En fait, le moteur JS ne gère pas directement les requêtes réseau. Il appelle simplement l'interface de requête réseau du navigateur, et le navigateur envoie des requêtes réseau et surveille les données renvoyées. L'essence des capacités asynchrones de JavaScript réside dans les capacités multithread du navigateur ou du nœud.
rappel
La fonction exécutée dans le futur est généralement appelée rappel. L’utilisation du mode de rappel asynchrone résout le problème de blocage, mais entraîne également d’autres problèmes. Au début, nos fonctions étaient écrites de haut en bas et exécutées de haut en bas. Ce mode "linéaire" est très cohérent avec nos habitudes de pensée, mais maintenant il est interrompu par le rappel ! Dans le morceau de code ci-dessus, il ignore désormais la tâche B et exécute la tâche C en premier ! Ce type de code « non linéaire » asynchrone sera plus difficile à lire que le code « linéaire » synchrone, et donc plus susceptible de générer des bugs.
Essayez de juger l'ordre d'exécution du code suivant. Vous comprendrez mieux que le code « non linéaire » est plus difficile à lire que le code « linéaire ».
A(); ajax('url1', function(){ B(); ajax('url2', function(){ C(); } D(); }); E(); // A => E => B => D => C
Dans ce code, l'ordre d'exécution de haut en bas est perturbé par le Callback. Notre ligne de mire lors de la lecture du code est A => B => C => D => E
, mais l'ordre d'exécution est A => E => B => D => C
C'est le mauvais côté du code non linéaire.
En déplaçant à l'avance les tâches exécutées après ajax
, il est plus facile de comprendre l'ordre d'exécution du code. Bien que le code semble moche en raison de l'imbrication, l'ordre d'exécution est désormais « linéaire » de haut en bas. Cette technique est très utile lors de l’écriture de plusieurs codes imbriqués.
A(); E(); ajax('url1', function(){ B(); D(); ajax('url2', function(){ C(); } }); // A => E => B => D => C
Le code précédent gère uniquement le rappel de réussite et ne gère pas le rappel d'exception. Ensuite, ajoutez le rappel de gestion des exceptions, puis discutez de la question de l'exécution « linéaire » du code. Après avoir ajouté le rappel de gestion des exceptions à
A(); ajax('url1', function(){ B(); ajax('url2', function(){ C(); },function(){ D(); }); },function(){ E(); });
, la fonction de rappel de réussite B et la fonction de rappel d'exception E de url1
sont séparées. Cette situation « non linéaire » apparaît à nouveau.
Dans node, afin de résoudre le problème « non linéaire » causé par des rappels anormaux, une stratégie d'erreur d'abord a été formulée. Le premier paramètre de rappel dans le nœud est spécifiquement utilisé pour déterminer si une exception se produit.
A(); get('url1', function(error){ if(error){ E(); }else { B(); get('url2', function(error){ if(error){ D(); }else{ C(); } }); } });
À ce stade, le problème « non linéaire » causé par le rappel a été pratiquement résolu. Malheureusement, en utilisant l'imbrication de rappel, couche par couche if else
et les fonctions de rappel, une fois que le nombre de couches imbriquées augmente, ce n'est pas très pratique à lire. De plus, une fois qu'une exception se produit lors du rappel, l'exception ne peut être gérée que dans la fonction de rappel actuelle.
promise
Dans l'histoire de l'évolution asynchrone de JavaScript, une série de bibliothèques ont émergé pour résoudre les lacunes du rappel, et Promise est devenu le gagnant final et a été introduit avec succès dans ES6. Cela fournira une meilleure manière d'écrire "linéaire" et résoudra le problème selon lequel les exceptions asynchrones ne peuvent être interceptées que dans le rappel actuel.
La promesse est comme un intermédiaire qui promet de renvoyer un résultat asynchrone fiable. Tout d'abord, Promise signe un accord avec l'interface asynchrone. En cas de succès, la fonction resolve
est appelée pour notifier Promise. Lorsqu'une exception se produit, reject
est appelée pour notifier Promise. D'un autre côté, Promise et callback signent également un accord, et Promise renverra des valeurs de confiance aux rappels enregistrés dans then
et catch
à l'avenir.
// 创建一个 Promise 实例(异步接口和 Promise 签订协议) var promise = new Promise(function (resolve,reject) { ajax('url',resolve,reject); }); // 调用实例的 then catch 方法 (成功回调、异常回调与 Promise 签订协议) promise.then(function(value) { // success }).catch(function (error) { // error })
Promise 是个非常不错的中介,它只返回可信的信息给 callback。它对第三方异步库的结果进行了一些加工,保证了 callback 一定会被异步调用,且只会被调用一次。
var promise1 = new Promise(function (resolve) { // 可能由于某些原因导致同步调用 resolve('B'); }); // promise依旧会异步执行 promise1.then(function(value){ console.log(value) }); console.log('A'); // A B (先 A 后 B) var promise2 = new Promise(function (resolve) { // 成功回调被通知了2次 setTimeout(function(){ resolve(); },0) }); // promise只会调用一次 promise2.then(function(){ console.log('A') }); // A (只有一个) var promise3 = new Promise(function (resolve,reject) { // 成功回调先被通知,又通知了失败回调 setTimeout(function(){ resolve(); reject(); },0) }); // promise只会调用成功回调 promise3.then(function(){ console.log('A') }).catch(function(){ console.log('B') }); // A(只有A)
介绍完 Promise 的特性后,来看看它如何利用链式调用,解决异步代码可读性的问题的。
var fetch = function(url){ // 返回一个新的 Promise 实例 return new Promise(function (resolve,reject) { ajax(url,resolve,reject); }); } A(); fetch('url1').then(function(){ B(); // 返回一个新的 Promise 实例 return fetch('url2'); }).catch(function(){ // 异常的时候也可以返回一个新的 Promise 实例 return fetch('url2'); // 使用链式写法调用这个新的 Promise 实例的 then 方法 }).then(function() { C(); // 继续返回一个新的 Promise 实例... }) // A B C ...
如此反复,不断返回一个 Promise 对象,再采用链式调用的方式不断地调用。使 Promise 摆脱了 callback 层层嵌套的问题和异步代码“非线性”执行的问题。
Promise 解决的另外一个难点是 callback 只能捕获当前错误异常。Promise 和 callback 不同,每个 callback 只能知道自己的报错情况,但 Promise 代理着所有的 callback,所有 callback 的报错,都可以由 Promise 统一处理。所以,可以通过catch
来捕获之前未捕获的异常。
Promise 解决了 callback 的异步调用问题,但 Promise 并没有摆脱 callback,它只是将 callback 放到一个可以信任的中间机构,这个中间机构去链接我们的代码和异步接口。
异步(async)函数
异步(async)函数是 ES7 的一个新的特性,它结合了 Promise,让我们摆脱 callback 的束缚,直接用类同步的“线性”方式,写异步函数。
声明异步函数,只需在普通函数前添加一个关键字 async
即可,如async function main(){}
。在异步函数中,可以使用await
关键字,表示等待后面表达式的执行结果,一般后面的表达式是 Promise 实例。
async function main{ // timer 是在上一个例子中定义的 var value = await timer(100); console.log(value); // done (100ms 后返回 done) } main();
异步函数和普通函数一样调用 main()
。调用后,会立即执行异步函数中的第一行代码 var value = await timer(100)
。等到异步执行完成后,才会执行下一行代码。
除此之外,异步函数和其他函数基本类似,它使用try...catch
来捕捉异常。也可以传入参数。但不要在异步函数中使用return
来返回值。
var timer = new Promise(function create(resolve,reject) { if(typeof delay !== 'number'){ reject(new Error('type error')); } setTimeout(resolve,delay,'done'); }); async function main(delay){ try{ var value1 = await timer(delay); var value2 = await timer(''); var value3 = await timer(delay); }catch(err){ console.error(err); // Error: type error // at create (<anonymous>:5:14) // at timer (<anonymous>:3:10) // at A (<anonymous>:12:10) } } main(0);
异步函数也可以被当作值,传入普通函数和异步函数中执行。但是在异步函数中,使用异步函数时要注意,如果不使用await
,异步函数会被同步执行。
async function main(delay){ var value1 = await timer(delay); console.log('A') } async function doAsync(main){ main(0); console.log('B') } doAsync(main); // B A
这个时候打印出来的值是 B A
。说明 doAsync
函数并没有等待 main
的异步执行完毕就执行了 console
。如果要让 console
在main
的异步执行完毕后才执行,我们需要在main
前添加关键字await
。
async function main(delay){ var value1 = await timer(delay); console.log('A') } async function doAsync(main){ await main(0); console.log('B') } doAsync(main); // A B
由于异步函数采用类同步的书写方法,所以在处理多个并发请求,新手可能会像下面一样书写。这样会导致url2
的请求必需等到url1
的请求回来后才会发送。
var fetch = function (url) { return new Promise(function (resolve,reject) { ajax(url,resolve,reject); }); } async function main(){ try{ var value1 = await fetch('url1'); var value2 = await fetch('url2'); conosle.log(value1,value2); }catch(err){ console.error(err) } } main();
使用Promise.all
的方法来解决这个问题。Promise.all
用于将多个Promise实例,包装成一个新的 Promis e实例,当所有的 Promise 成功后才会触发Promise.all
的resolve
函数,当有一个失败,则立即调用Promise.all
的reject
函数。
var fetch = function (url) { return new Promise(function (resolve,reject) { ajax(url,resolve,reject); }); } async function main(){ try{ var arrValue = await Promise.all[fetch('url1'),fetch('url2')]; conosle.log(arrValue[0],arrValue[1]); }catch(err){ console.error(err) } } main();
目前使用 Babel 已经支持 ES7 异步函数的转码了,大家可以在自己的项目中开始尝试。
以上就是JavaScript 异步进化史的代码实例详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Comprendre le fonctionnement du moteur JavaScript en interne est important pour les développeurs car il aide à écrire du code plus efficace et à comprendre les goulots d'étranglement des performances et les stratégies d'optimisation. 1) Le flux de travail du moteur comprend trois étapes: analyse, compilation et exécution; 2) Pendant le processus d'exécution, le moteur effectuera une optimisation dynamique, comme le cache en ligne et les classes cachées; 3) Les meilleures pratiques comprennent l'évitement des variables globales, l'optimisation des boucles, l'utilisation de const et de locations et d'éviter une utilisation excessive des fermetures.

Python convient plus aux débutants, avec une courbe d'apprentissage en douceur et une syntaxe concise; JavaScript convient au développement frontal, avec une courbe d'apprentissage abrupte et une syntaxe flexible. 1. La syntaxe Python est intuitive et adaptée à la science des données et au développement back-end. 2. JavaScript est flexible et largement utilisé dans la programmation frontale et côté serveur.

Python et JavaScript ont leurs propres avantages et inconvénients en termes de communauté, de bibliothèques et de ressources. 1) La communauté Python est amicale et adaptée aux débutants, mais les ressources de développement frontal ne sont pas aussi riches que JavaScript. 2) Python est puissant dans les bibliothèques de science des données et d'apprentissage automatique, tandis que JavaScript est meilleur dans les bibliothèques et les cadres de développement frontaux. 3) Les deux ont des ressources d'apprentissage riches, mais Python convient pour commencer par des documents officiels, tandis que JavaScript est meilleur avec MDNWEBDOCS. Le choix doit être basé sur les besoins du projet et les intérêts personnels.

Le passage de C / C à JavaScript nécessite de s'adapter à la frappe dynamique, à la collecte des ordures et à la programmation asynchrone. 1) C / C est un langage dactylographié statiquement qui nécessite une gestion manuelle de la mémoire, tandis que JavaScript est dynamiquement typé et que la collecte des déchets est automatiquement traitée. 2) C / C doit être compilé en code machine, tandis que JavaScript est une langue interprétée. 3) JavaScript introduit des concepts tels que les fermetures, les chaînes de prototypes et la promesse, ce qui améliore la flexibilité et les capacités de programmation asynchrones.

Différents moteurs JavaScript ont des effets différents lors de l'analyse et de l'exécution du code JavaScript, car les principes d'implémentation et les stratégies d'optimisation de chaque moteur diffèrent. 1. Analyse lexicale: convertir le code source en unité lexicale. 2. Analyse de la grammaire: générer un arbre de syntaxe abstrait. 3. Optimisation et compilation: générer du code machine via le compilateur JIT. 4. Exécuter: Exécutez le code machine. Le moteur V8 optimise grâce à une compilation instantanée et à une classe cachée, SpiderMonkey utilise un système d'inférence de type, résultant en différentes performances de performances sur le même code.

Les applications de JavaScript dans le monde réel incluent la programmation côté serveur, le développement des applications mobiles et le contrôle de l'Internet des objets: 1. La programmation côté serveur est réalisée via Node.js, adaptée au traitement de demande élevé simultané. 2. Le développement d'applications mobiles est effectué par le reactnatif et prend en charge le déploiement multiplateforme. 3. Utilisé pour le contrôle des périphériques IoT via la bibliothèque Johnny-Five, adapté à l'interaction matérielle.

J'ai construit une application SAAS multi-locataire fonctionnelle (une application EdTech) avec votre outil technologique quotidien et vous pouvez faire de même. Premièrement, qu'est-ce qu'une application SaaS multi-locataire? Les applications saas multi-locataires vous permettent de servir plusieurs clients à partir d'un chant

Cet article démontre l'intégration frontale avec un backend sécurisé par permis, construisant une application fonctionnelle EdTech SaaS en utilisant Next.js. Le frontend récupère les autorisations des utilisateurs pour contrôler la visibilité de l'interface utilisateur et garantit que les demandes d'API adhèrent à la base de rôles


Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Version crackée d'EditPlus en chinois
Petite taille, coloration syntaxique, ne prend pas en charge la fonction d'invite de code

Version Mac de WebStorm
Outils de développement JavaScript utiles

Navigateur d'examen sécurisé
Safe Exam Browser est un environnement de navigation sécurisé permettant de passer des examens en ligne en toute sécurité. Ce logiciel transforme n'importe quel ordinateur en poste de travail sécurisé. Il contrôle l'accès à n'importe quel utilitaire et empêche les étudiants d'utiliser des ressources non autorisées.

SublimeText3 version anglaise
Recommandé : version Win, prend en charge les invites de code !

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP