Il y a quelques années, les rappels étaient le seul moyen d'exécuter du code asynchrone en JavaScript. Il y a peu de problèmes avec les rappels eux-mêmes, le plus notable étant « l’enfer des rappels ».
Introduit dans ES6 Promesse comme solution à ces problèmes. Enfin, le mot-clé async/await
est introduit pour offrir une meilleure expérience et améliorer la lisibilité.
Même avec les nouvelles méthodes, il existe encore de nombreux modules et bibliothèques natifs qui utilisent des rappels. Dans cet article, nous verrons comment convertir les rappels JavaScript en promesses. La connaissance d'ES6 sera utile, car nous utiliserons des fonctionnalités telles que l'opérateur de propagation pour simplifier ce que nous devons faire.
Un rappel est un paramètre de fonction, qui se trouve être une fonction elle-même. Bien que nous puissions créer n'importe quelle fonction pour accepter une autre fonction, les rappels sont principalement utilisés pour les opérations asynchrones.
JavaScript est un langage interprété qui ne peut traiter qu'une seule ligne de code à la fois. Certaines tâches peuvent prendre beaucoup de temps, comme le téléchargement ou la lecture de fichiers volumineux, etc. JavaScript décharge ces tâches de longue durée vers le navigateur ou d'autres processus au sein de l'environnement Node.js. De cette façon, cela ne bloquera pas l’exécution d’autres codes.
Habituellement, les fonctions asynchrones acceptent les fonctions de rappel afin que leurs données puissent être traitées une fois terminées.
Par exemple, nous écrirons une fonction de rappel qui sera exécutée une fois que le programme aura lu avec succès le fichier sur le disque dur.
Vous devez donc préparer un fichier texte nommé sample.txt
, qui contient le contenu suivant :
Hello world from sample.txt
Ensuite, écrivez un simple script Node.js pour lire le fichier :
const fs = require('fs'); fs.readFile('./sample.txt', 'utf-8', (err, data) => { if (err) { // 处理错误 console.error(err); return; } console.log(data); }); for (let i = 0; i < 10; i++) { console.log(i); }
Après avoir exécuté le code, il affichera :
0 ... 8 9 Hello world from sample.txt
Si vous utilisez ce code, vous devriez voir 0..9
être affiché sur la console avant d'exécuter le rappel. Cela est dû au mécanisme de gestion asynchrone de JavaScript. Après avoir lu le fichier, le rappel pour afficher le contenu du fichier est appelé.
À propos, les rappels peuvent également être utilisés dans les méthodes synchrones. Par exemple, Array.sort()
acceptera une fonction de rappel qui vous permettra de personnaliser la façon dont les éléments sont triés.
Les fonctions qui acceptent les rappels sont appelées « fonctions d'ordre supérieur ».
Nous disposons désormais d'une meilleure méthode de rappel. Continuons donc à regarder ce qu'est Promise.
Promise a été introduit dans ECMAScript 2015 (ES6) pour améliorer l'expérience de programmation asynchrone. Comme son nom l'indique, la « valeur » ou « l'erreur » qu'un objet JavaScript renverra éventuellement doit être une promesse.
Une promesse a 3 états :
La plupart des promesses finissent par ressembler à ceci :
someAsynchronousFunction() .then(data => { // promise 被完成 console.log(data); }) .catch(err => { // promise 被拒绝 console.error(err); });
Les promesses sont très importantes dans le JavaScript moderne car elles sont liées au introduit dans ECMAScript 2016async/await
Les mots-clés sont utilisés ensemble. L'utilisation de async / await
élimine le besoin de rappels ou de then()
et catch()
pour écrire du code asynchrone.
Si vous deviez réécrire l'exemple précédent, il ressemblerait à ceci :
try { const data = await someAsynchronousFunction(); } catch(err) { // promise 被拒绝 console.error(err); }
Cela ressemble beaucoup à du JavaScript synchrone "normal". Les bibliothèques JavaScript les plus populaires et les nouveaux projets utilisent Promises avec le mot-clé async/await
.
Cependant, si vous mettez à jour une bibliothèque existante ou si vous rencontrez du code ancien, vous pourriez être intéressé par la migration d'une API basée sur le rappel vers une API basée sur la promesse, ce qui peut améliorer votre expérience de développement.
Examinons plusieurs façons de convertir les rappels en promesse.
La plupart des fonctions asynchrones qui acceptent les rappels dans Node.js (comme le module fs
) ont des implémentations standard Méthode : Passez le rappel comme dernier paramètre.
Par exemple, voici comment lire un fichier avec fs.readFile()
sans spécifier l'encodage du texte :
fs.readFile('./sample.txt', (err, data) => { if (err) { console.error(err); return; } console.log(data); });
Remarque : Si vous spécifiez utf-8
comme encodage, alors la sortie obtenue est une chaîne. Si non spécifié, la sortie est Buffer
.
De plus, le rappel passé à cette fonction doit accepter Error
car il s'agit du premier argument. Il peut y avoir n'importe quel nombre de sorties par la suite.
Si vous avez besoin d'une fonction convertie en Promise pour suivre ces règles, vous pouvez utiliser util.promisify , qui est un module Node.js natif qui contient des rappels vers Promise.
Importez d'abord le module ʻutil` :
const util = require('util');
Puis convertissez-le en promesse en utilisant la méthode promisify
:
const fs = require('fs'); const readFile = util.promisify(fs.readFile);
Maintenant, utilisez la fonction nouvellement créée comme promesse :
readFile('./sample.txt', 'utf-8') .then(data => { console.log(data); }) .catch(err => { console.log(err); });
Alternativement, vous pouvez utiliser le mot-clé async/await
donné dans l'exemple ci-dessous :
const fs = require('fs'); const util = require('util'); const readFile = util.promisify(fs.readFile); (async () => { try { const content = await readFile('./sample.txt', 'utf-8'); console.log(content); } catch (err) { console.error(err); } })();
Vous ne pouvez utiliser le mot-clé async
que dans les fonctions créées avec await
. C'est également la raison pour laquelle des wrappers de fonctions sont utilisés. Les wrappers de fonctions sont également appelés expressions de fonction immédiatement invoquées.
如果你的回调不遵循这个特定标准也不用担心。 util.promisify()
函数可让你自定义转换是如何发生的。
注意: Promise 在被引入后不久就开始流行了。 Node.js 已经将大部分核心函数从回调转换成了基于 Promise 的API。
如果需要用 Promise 处理文件,可以用 Node.js 附带的库(https://nodejs.org/docs/lates...)。
现在你已经了解了如何将 Node.js 标准样式回调隐含到 Promise 中。从 Node.js 8 开始,这个模块仅在 Node.js 上可用。如果你用的是浏览器或早期版本版本的 Node,则最好创建自己的基于 Promise 的函数版本。
让我们讨论一下怎样把回调转为 util.promisify()
函数的 promise。
思路是创建一个新的包含回调函数的 Promise 对象。如果回调函数返回错误,就拒绝带有该错误的Promise。如果回调函数返回非错误输出,就解决并输出 Promise。
先把回调转换为一个接受固定参数的函数的 promise 开始:
const fs = require('fs'); const readFile = (fileName, encoding) => { return new Promise((resolve, reject) => { fs.readFile(fileName, encoding, (err, data) => { if (err) { return reject(err); } resolve(data); }); }); } readFile('./sample.txt') .then(data => { console.log(data); }) .catch(err => { console.log(err); });
新函数 readFile()
接受了用来读取 fs.readFile()
文件的两个参数。然后创建一个新的 Promise 对象,该对象包装了该函数,并接受回调,在本例中为 fs.readFile()
。
要 reject
Promise 而不是返回错误。所以代码中没有立即把数据输出,而是先 resolve
了Promise。然后像以前一样使用基于 Promise 的 readFile()
函数。
接下来看看接受动态数量参数的函数:
const getMaxCustom = (callback, ...args) => { let max = -Infinity; for (let i of args) { if (i > max) { max = i; } } callback(max); } getMaxCustom((max) => { console.log('Max is ' + max) }, 10, 2, 23, 1, 111, 20);
第一个参数是 callback 参数,这使它在接受回调的函数中有点与众不同。
转换为 promise 的方式和上一个例子一样。创建一个新的 Promise 对象,这个对象包装使用回调的函数。如果遇到错误,就 reject
,当结果出现时将会 resolve
。
我们的 promise 版本如下:
const getMaxPromise = (...args) => { return new Promise((resolve) => { getMaxCustom((max) => { resolve(max); }, ...args); }); } getMaxCustom(10, 2, 23, 1, 111, 20) .then(max => console.log(max));
在创建 promise 时,不管函数是以非标准方式还是带有许多参数使用回调都无关紧要。我们可以完全控制它的完成方式,并且原理是一样的。
尽管现在回调已成为 JavaScript 中利用异步代码的默认方法,但 Promise 是一种更现代的方法,它更容易使用。如果遇到了使用回调的代码库,那么现在就可以把它转换为 Promise。
在本文中,我们首先学到了如何 在Node.js 中使用 utils.promisfy()
方法将接受回调的函数转换为 Promise。然后,了解了如何创建自己的 Promise 对象,并在对象中包装了无需使用外部库即可接受回调的函数。这样许多旧 JavaScript 代码可以轻松地与现代的代码库和混合在一起。
更多编程相关知识,请访问:编程学习!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!