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'
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中文網其他相關文章!