Promise 化回调式函数

本文介绍Node.js 8中util.promisify的功能,该工具允许开发者轻松地将传统的回调式API转换为基于Promise的API。文章详细解释了如何使用此工具,并展示了如何自定义Promise版本的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Node.js 8 提供了新的工具函数:util.promisify,用于把形如 (err, value) => ... 的回调式函数转换为 Promise 版本。

基本使用

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

const stat = util.promisify(fs.stat);

stat('.').then((stats) => {
  // Do something with `stats`
}).catch((error) => {
  // Handle the error.
});
复制代码

当然,也可以使用 Node 8 另一个新功能 async function 调用:

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

const stat = util.promisify(fs.stat);

async function callStat() {
  const stats = await stat('.');
  console.log(`This directory is owned by ${stats.uid}`);
}
复制代码

自定义函数的 Promise 版本

通过设置 util.promisify.custom symbol,可以自定义 util.promisify() 的返回值:

const util = require('util');

function doSomething(foo, callback) {
  // ...
}

doSomething[util.promisify.custom] = (foo) => {
  return getPromiseSomehow();
};

const promisified = util.promisify(doSomething);

console.log(promisified === doSomething[util.promisify.custom]);
// prints 'true'
复制代码

自定义 Promise symbol 一般用于源函数不遵循 (err, value) => ... 回调的场景,比如 (foo, onSuccessCallback, onErrorCallback) 式回调的函数:

doSomething[util.promisify.custom] = (foo) => {
  return new Promise((resolve, reject) => {
    doSomething(foo, resolve, reject);
  });
};
复制代码

回调函数中包含超过两个参数的函数

诸如以下函数,回调中除了 err 参数,还包含多个参数:

  • child_process.exec
  • child_process.execFile
  • dns.lookup
  • dns.lookupService
  • fs.read
  • fs.write

经过 util.promisify 处理的 Promise 版本会将多个参数组装成对象返回。

例如,dns.lookup() 的回调有三个参数:

  • err: Error
  • address: 字符串
  • family: 整数

Promise 化后,返回 {address: '', family: 3} 这样的对象:

const util = require('util');
const dns = require('dns');
const lookupAsync = util.promisify(dns.lookup);

lookupAsync('nodejs.org')
  .then(obj => console.log(obj));
   // { address: '104.20.23.46', family: 4 }
复制代码

老版本 Node

Polyfill: util.promisify 模块

npm install util.promisify
复制代码
const util = require('util');
require('util.promisify').shim();

const fs = require('fs');
const readFileAsync = util.promisify(fs.readFile);
复制代码

pify

pify 是一个小而美的 Promise 化工具,处理了一些有用的细节,如自动 this 绑定,这是内置的 util.promisify 中没有的。

const fs = require('fs');
const pify = require('pify');

// Promisify a single function
pify(fs.readFile)('package.json', 'utf8').then(data => {
  console.log(JSON.parse(data).name);
  //=> 'pify'
});

// Promisify all methods in a module
pify(fs).readFile('package.json', 'utf8').then(data => {
  console.log(JSON.parse(data).name);
  //=> 'pify'
});
复制代码

参考链接




### Promise回调函数的区别及用法 在JavaScript中,异步编程是处理需要等待的操作(如网络请求、文件读取等)的核心机制。回调函数Promise是两种常见的异步编程方式,但它们的设计理念和使用场景有所不同。 #### 1. 回调函数 回调函数JavaScript异步编程的基础[^2]。它通过将一个函数作为参数传递给另一个函数,并在异步操作完后执行该函数来实现异步行为。尽管回调函数简单直接,但在复杂的异步场景下容易导致“调地狱”问题,即嵌套的回调函数层次过深,代码难以阅读和维护。 以下是一个使用回调函数的示例: ```javascript function fetchData(callback) { setTimeout(() => { const data = "数据已准备好"; callback(data); }, 1000); } fetchData((result) => { console.log(result); // 输出: 数据已准备好 }); ``` #### 2. Promise 为了克服回调函数的缺点,JavaScript引入了Promise对象[^3]。Promise提供了一种更简洁和可维护的异步编程方式。它代表了一个异步操作的最终完或失败,并返一个结果值。Promise有三种状态:`pending`(待定)、`fulfilled`(已完)和`rejected`(已拒绝)。通过`.then()`和`.catch()`方法,可以分别处理功和失败的情况。 以下是一个使用Promise的示例: ```javascript function fetchDataWithPromise() { return new Promise((resolve, reject) => { setTimeout(() => { const data = "数据已准备好"; resolve(data); // 模拟功 // reject("发生错误"); // 模拟失败 }, 1000); }); } fetchDataWithPromise() .then((result) => { console.log(result); // 输出: 数据已准备好 }) .catch((error) => { console.error(error); // 处理错误 }); ``` #### 3. 区别总结 - **可读性**:回调函数在简单场景下易于理解,但随着嵌套层级增加,代码可读性会显著下降。Promise通过链式调用简了复杂的异步流程[^3]。 - **错误处理**:回调函数通常需要手动检查错误并传递错误信息,而Promise内置了`.catch()`方法,能够集中处理整个异步链中的错误[^4]。 - **组合能力**:Promise支持`Promise.all()`和`Promise.race()`等方法,方便同时处理多个异步操作[^3]。 #### 4. 示例对比 以下是使用回调函数Promise实现相同功能的对比: **回调函数版本**: ```javascript function getUserInfo(userId, callback) { setTimeout(() => { const userInfo = { id: userId, name: '小明', age: 18 }; callback(userInfo); }, 1000); } getUserInfo(123, (user) => { console.log(user); // 输出: { id: 123, name: '小明', age: 18 } }); ``` **Promise版本**: ```javascript function getUserInfoWithPromise(userId) { return new Promise((resolve, reject) => { setTimeout(() => { const userInfo = { id: userId, name: '小明', age: 18 }; resolve(userInfo); }, 1000); }); } getUserInfoWithPromise(123) .then((user) => { console.log(user); // 输出: { id: 123, name: '小明', age: 18 } }) .catch((error) => { console.error(error); }); ``` ### 结论 虽然回调函数JavaScript异步编程的基础[^2],但Promise提供了更优雅的解决方案,特别是在复杂场景下能够显著提升代码的可读性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值