Maison  >  Article  >  interface Web  >  Un examen approfondi de la méthode promisify() du module util Node.js

Un examen approfondi de la méthode promisify() du module util Node.js

青灯夜游
青灯夜游avant
2021-08-27 10:33:233204parcourir

Un examen approfondi de la méthode promisify() du module util Node.js

Node.js Le module util intégré a un promisify() méthodeutil 模块有一个 promisify() 方法,该方法将基于回调的函数转换为基于 Promise 的函数。这使您可以将 Promise 链和 async/await 与基于回调的 API 结合使用。

例如,Node.js 的 fs 模块在读取文件时,需要使用回调:

const fs = require('fs')

fs.readFile('./package.json', function callback(err, buf) {
  const obj = JSON.parse(buf.toString('utf8'))
  console.log(obj.name) // 'Example' -> package.json 包名
})

我们可以使用 util.promisify()fs.readFile() 的回调函数转换为返回 Promise 函数:

const fs = require('fs')
const util = require('util')

// 将 fs.readFile() 转换为一个接受相同参数但返回 Promise 的函数。
const readFile = util.promisify(fs.readFile)

// 现在可以将 readFile() 与 await 一起使用!
const buf = await readFile('./package.json')

const obj = JSON.parse(buf.toString('utf8'))
console.log(obj.name) // 'Example'

promisify 是如何工作的?

util.promisify() 在后台是如何工作的?npm 上有一个 polyfill,您可以在这里阅读完整的实现。您也可以在这里找到 Node.js 的实现,不过为了便于理解,polyfill 更易于阅读。【推荐学习:《nodejs 教程》】

util.promisify() 背后的关键思想是向传入的参数添加回调函数。该回调函数解析或拒绝 promisified 函数返回的 Promise。

为了便于理解,下面是一个非常简化的 util.promisify() 自定义实现示例:

const fs = require('fs')

// util.promisify() 的简化实现。不包括所有情况,不要在 prod 环境中使用此选项!
function promisify(fn) {
  return function() {
    const args = Array.prototype.slice.call(arguments)
    return new Promise((resolve, reject) => {
      fn.apply(this, [].concat(args).concat([(err, res) => {
        if (err != null) {
          return reject(err)
        }
        resolve(res)
      }]))
    })
  }
}

// 将 fs.readFile() 转换为一个接受相同参数但返回 Promise 的函数。
const readFile = promisify(fs.readFile)

// 现在可以将 readFile() 与 await 一起使用!
const buf = await readFile('./package.json')

const obj = JSON.parse(buf.toString('utf8'))
console.log(obj.name) // 'Example'

那么这是什么意思呢?首先,util.promisify()向传入的参数添加 1 个额外参数,然后使用这些新参数调用原始函数。这意味着底层函数需要支持该数量的参数。因此,如果您要调用myFn()具有 2 个类型参数的promisified 函数 [String, Object],请确保原始函数支持[String, Object, Function]

那么这意味着什么呢?首先,util.promisify() 向传入的参数添加一个额外参数,然后使用这些新参数调用原始函数。这意味着基础函数需要支持该数量的参数。因此,如果您使用 [String, Object] 类型的 2 个参数调用 promisified 函数 myFn(),请确保原始函数支持 [String, Object, Function]

其次,util.promisify() 对函数上下文(this)有影响。

丢失上下文

丢失上下文(this)意味着函数调用以错误的值结束。丢失上下文是转换函数的常见问题:

class MyClass {
  myCallbackFn(cb) {
    cb(null, this)
  }
}

const obj = new MyClass()
const promisified = require('util').promisify(obj.myCallbackFn)

const context = await promisified()
console.log(context) // 打印 undefined 而不是 MyClass 实例!

请记住,this, qui convertit les fonctions basées sur le rappel en fonctions basées sur la promesse. Cela vous permet d'utiliser des chaînes Promise et async/await avec des API basées sur le rappel.

Par exemple, le module fs de Node.js doit utiliser un rappel lors de la lecture d'un fichier :

class MyClass {
  myCallbackFn(cb) {
    cb(null, this)
  }
}

const obj = new MyClass()
// 保留上下文,因为 promisified 是 obj 的属性
obj.promisified = require('util').promisify(obj.myCallbackFn)

const context = await obj.promisified()
console.log(context === obj) // true
Nous pouvons utiliser util.promisify() pour convertir fs La fonction de rappel de .readFile() est convertie en une fonction de retour de promesse :

rrreee

Comment fonctionne la promesse ?

🎜util.promisify() Comment ça marche en coulisses ? Il existe un polyfill🎜 sur npm que vous pouvez lire ici Implémentation complète 🎜. Vous pouvez également le trouver ici Implémentation Node.js🎜, mais pour faciliter la compréhension, polyfill est plus facile à lire. [Apprentissage recommandé : "tutoriel nodejs🎜"]🎜🎜 L'idée clé derrière util.promisify() est Ajoute une fonction de rappel aux paramètres passés 🎜. Cette fonction de rappel résout ou rejette la promesse renvoyée par la fonction promise. 🎜🎜Pour faciliter la compréhension, voici un exemple d'implémentation personnalisé très simplifié de util.promisify() : 🎜rrreee🎜Alors, qu'est-ce que cela signifie ? Tout d'abord, util.promisify() ajoute 1 paramètre supplémentaire aux paramètres transmis, puis appelle la fonction d'origine avec ces nouveaux paramètres. Cela signifie que la fonction sous-jacente doit prendre en charge ce nombre d'arguments. Donc, si vous appelez myFn() une fonction promise [String, Object] avec 2 paramètres de type, assurez-vous que la fonction d'origine prend en charge [String, Object, Function ]. 🎜🎜Alors qu’est-ce que cela signifie ? Tout d'abord, util.promisify() ajoute un paramètre supplémentaire aux paramètres transmis, puis appelle la fonction d'origine avec ces nouveaux paramètres. Cela signifie que la fonction sous-jacente doit prendre en charge ce nombre de paramètres. Par conséquent, si vous appelez la fonction promise myFn() avec 2 arguments de type [String, Object], assurez-vous que la fonction d'origine prend en charge [String, Object , Fonction ]. 🎜🎜Deuxièmement, util.promisify() a un impact sur le contexte de la fonction (this). 🎜

Contexte perdu

🎜Contexte perdu (this) signifie que l'appel de fonction se termine avec une valeur incorrecte. La perte de contexte est un problème courant avec les fonctions de conversion : 🎜rrreee🎜 N'oubliez pas que this est tout objet qui contient des propriétés lorsque la fonction est appelée. Vous pouvez ainsi préserver le contexte en définissant la fonction promise sur une propriété du même objet : 🎜rrreee🎜Pour plus de connaissances sur la programmation, veuillez visiter : 🎜Vidéos de programmation🎜 ! ! 🎜

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer