首頁  >  文章  >  web前端  >  深入了解Node.js util模組的promisify()方法

深入了解Node.js util模組的promisify()方法

青灯夜游
青灯夜游轉載
2021-08-27 10:33:233208瀏覽

深入了解Node.js util模組的promisify()方法

Node.js 內建的util 模組有一個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 包含函數被呼叫時的屬性的任何物件。因此,您可以透過將 promisified 函數設定為相同物件的屬性來保留上下文:

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

更多程式設計相關知識,請造訪:程式設計影片! !

以上是深入了解Node.js util模組的promisify()方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除