Home  >  Article  >  Web Front-end  >  An in-depth look at the promisify() method of the Node.js util module

An in-depth look at the promisify() method of the Node.js util module

青灯夜游
青灯夜游forward
2021-08-27 10:33:233175browse

An in-depth look at the promisify() method of the Node.js util module

Node.js The built-in util module has a promisify() method, This method converts a callback-based function into a Promise-based function. This allows you to use Promise chains and async/await with callback-based APIs.

For example, the fs module of Node.js needs to use a callback when reading a file:

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 包名
})

We can use util.promisify() Convert the callback function of fs.readFile() into a Promise-returning function:

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'

How does promisify work?

util.promisify() How does it work behind the scenes? There is a polyfill on npm and you can read the full implementation here. You can also find the Node.js implementation here, but for ease of understanding, the polyfill is easier to read. [Recommended learning: "nodejs Tutorial"]

util.promisify() The key idea behind it is Add a callback function to the incoming parameters. This callback function resolves or rejects the Promise returned by the promisified function.

For ease of understanding, the following is a very simplified util.promisify() custom implementation example:

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'

So what does this mean? First, util.promisify()adds 1 extra parameter to the passed in parameters and then calls the original function with these new parameters. This means that the underlying function needs to support that number of parameters. So if you are calling myFn() a promisified function with 2 type parameters [String, Object], make sure the original function supports [String, Object, Function] .

So what does this mean? First, util.promisify() adds an extra parameter to the passed in parameters, then calls the original function with these new parameters. This means that the underlying function needs to support that number of parameters. So if you call the promisified function myFn() with 2 arguments of type [String, Object], make sure the original function supports [String, Object, Function].

Secondly, util.promisify() has an impact on the function context (this).

Lost context

Lost context (this) means that the function call ended with the wrong value. Losing context is a common problem with cast functions:

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 实例!

Remember that this is any object that contains properties when the function is called. Therefore, you can preserve the context by setting the promisified function to a property of the same object:

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

For more programming related knowledge, please visit:Programming Video! !

The above is the detailed content of An in-depth look at the promisify() method of the Node.js util module. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete