npm包 promise-to-async 使用教程

前言

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


纠错反馈