前言
JavaScript 中 async/await 已经成为了解决异步问题的标配,但是在遗留应用或者是需要进行大量数据处理的情况下,callback 和 Promise 仍然是比较常见的。而本文推荐的 npm 包 promise-to-async 就是帮助我们将 callback 和 Promise 转化成 async/await 的利器。
何时使用
当我们需要将一个 callback/Promise 异步函数转化为 async/await 函数时,我们可以使用 promise-to-async,同时也可以将在 callback 和 Promise 之间进行不断转换的代码进行简化和优化。比如一个普通的 callback 函数:
function getUserById(id, callback) { setTimeout(() => { if (id === 1) { callback({ id: 1, name: "Alice" }) } else if (id === 2) { callback({ id: 2, name: "Bob" }) } else { callback(null) } }, 1000) }
使用 promise-to-async 包后,我们代码会变得更加优雅:
const promiseToAsync = require('promise-to-async'); const getUserByIdAsync = promiseToAsync(getUserById); const user = await getUserByIdAsync(1);
安装
使用 npm 可以非常方便地安装 promise-to-async 包:
npm install promise-to-async
使用示例
在上文中我们已经介绍了 promise-to-async 的基本使用方法。下面我们来看一些高级的用法示例。
处理 Promise 和 Callback 混合的函数
当我们在处理一些遗留代码时,经常会遇到 Promise 和 Callback 混合的函数,这时候我们需要将其转化为 async/await 函数,比如:
function getUserById(id, callback) { if (id === 1) { callback(null, { id: 1, name: 'Alice' }) } else if (id === 2) { callback(null, { id: 2, name: 'Bob' }) } else { return Promise.reject('User not found') } } const promiseToAsync = require('promise-to-async'); const getUserNameByIdAsync = promiseToAsync((id, callback) => { getUserById(id, (err, user) => { if (err) { return callback(err) } callback(null, user.name) }) });
这种情况下,我们需要对传入的 callback 进行处理,通过 promise-to-async 将其转化为 async/await 形式的函数。
处理带 Error 的回调函数
我们经常会遇到一些以 callback 的方式返回错误信息的函数,比如:
function add(a, b, callback) { if (typeof a !== 'number' || typeof b !== 'number') { const err = new Error('Invalid parameters'); callback(err); return; } callback(null, a + b); }
使用 promise-to-async 的方式进行转化:
const promiseToAsync = require('promise-to-async'); const addAsync = promiseToAsync(add); async function test() { const result1 = await addAsync(1, 2); console.log(result1); // 3 try { await addAsync('a', 'b'); } catch (error) { console.log(error.message); // Invalid parameters } }
处理错误编码的回调函数
有时候我们遇到的回调函数返回的错误信息是一串编码,需要进行解析后才能使用,比如:
function login(username, password, callback) { const code = Math.round(Math.random() * 100); if (code === 0) { callback('1001'); return; } const userInfo = { username, password }; callback(null, userInfo); }
使用 promise-to-async 实现转化:
const promiseToAsync = require('promise-to-async'); const loginAsync = promiseToAsync(login, { promisifyError: (code) => { switch (code) { case '1001': return 'Invalid username or password'; default: return `Unknown error ${code}`; } } }); loginAsync('user1', 'pass1') .then(userInfo => { console.log(userInfo); // { username: 'user1', password: 'pass1' } }) .catch(error => { console.error(error); // Invalid username or password });
处理多个回调函数参数的场景
一些库中的回调函数需要返回多个值,这时候可以利用 promise-to-async 进行转化和解构:
function getUser(id, callback) { callback(null, { username: 'user' + id, age: id * 10, }, 'id-' + id); } const promiseToAsync = require('promise-to-async'); const getUserAsync = promiseToAsync(getUser); async function test(){ const [userInfo, userMeta] = await getUserAsync(100); console.log(userInfo); // { username: 'user100', age: 1000 } console.log(userMeta); // id-100 }
结语
promise-to-async 是一个非常实用的轻量级 npm 包,可以帮助我们解决一些 callback/Promise 异步函数在处理数据量大或遗留应用时的问题,同时还能让我们在使用 async/await 时代码更加整洁、优雅。代码示例中的异步函数和回调函数可以是任何格式,只需要保证有 callback/Promise 形式的传参即可。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/600673defb81d47349e53bae