await-to-js 基本使用 & 源码分析

接上文

连续串行请求的方案对比,优雅的 await-to-js

故事背景

常规情况下,业务一般拆分到较小的组件,一般涉及 1-2 个请求,使用单个函数等调用及处理错误会比较清晰,但当连续多个请求依次串行调用,业务逻辑可能就是下面这种结构了。

不仅包含多个维度,每个维度的各个需求连续调用,等等层层叠加之后,代码如果用回调甚至 Promise 链式调用的方式逐渐产生结构不清晰或者代码冗余的问题,所以 async & await 应运而生,这里的 await-to-js 就是其中一个优化选择。

优雅的 demo

为什么选择 await-to-js ? 看下面的 demo 就知道它有多优雅了。

js 复制代码
import { to } from "await-to-js";

// 底层原子函数
async function generate() {
  return axios.get(generateUrl);
}

async function match(payload) {
  return axios.post(matchUrl, payload);
}

async function save(payload) {
  return axios.post(saveUrl, payload);
}


// 流程处理中心(数据)
async function flow() {
  const [err1, r1] = await to(generate());
  if (err1) return [err1]; // return axiosError(err1)

  const [err2, r2] = await to(match(r1.data.data));
  if (err2) return [err2];

  const [err3, r3] = await to(save(r2.data.data));
  if (err3) return [err3];

  return [null, r3];
}

// 用户触发函数,(状态管理),loading 之类
async function onClick() {
  const [err, result] = await flow();
  if (err) axiosError(err);
  else setResult(result);
}

源码分析

源码包含注释总共 22 行,一个高阶包裹函数 to

  • 传入一个 Promise(axios)
  • 返回一个 Promise;
  • 成功 await 得到结果 null,data; 第一个返回 null 可以理解为,第一个位置赋值为 null,而不是没有
  • 失败 await 得到结果 err,undefined; 第二个返回 undefined 可以理解为,没有第二个数据,没经历赋值,所以还是 undefined 类型
typescript 复制代码
/**
 * @param { Promise } promise
 * @param { Object= } errorExt - Additional Information you can pass to the err object
 * @return { Promise }
 */
export function to<T, U = Error> (
  promise: Promise<T>,
  errorExt?: object
): Promise<[U, undefined] | [null, T]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[U, undefined]>((err: U) => {
      if (errorExt) {
        const parsedError = Object.assign({}, err, errorExt);
        return [parsedError, undefined];
      }

      return [err, undefined];
    });
}

export default to;

to 函数一般结合 await 使用,比如上面的流程处理函数,await 可以接收到 promise 的回调函数的返回结果,无论是 then 还是 catch

js 复制代码
// 流程处理中心(数据)
async function flow() {
  const [err1, r1] = await to(generate());
  if (err1) return [err1]; // return axiosError(err1)

  const [err2, r2] = await to(match(r1.data.data));
  if (err2) return [err2];

  const [err3, r3] = await to(save(r2.data.data));
  if (err3) return [err3];

  return [null, r3];
}

提出疑问,下回分析

从上面的源码我们应该可以提出几个疑问:

比如,为什么 await 可以接收 catch 和 then 的第一个函数返回结果,而没有抛异常呢?

比如,promise 的 catch 可以连续多个调用吗?

比如,promise 的 catch 和 finally 区别是什么?都会执行吗?

...

相关推荐
Hilaku几秒前
前端架构师的克制:什么时候该坚决对新技术说不?
前端·javascript·程序员
陈随易26 分钟前
前端项目部署只要30秒
前端·后端·程序员
本末倒置18328 分钟前
从 Vue CLI 迁移到 Rsbuild 后,JSX 突然全挂了?一次排查记录
前端
古夕29 分钟前
多应用同域部署下 Favicon 异常问题排查与治理
前端·javascript
YIAN30 分钟前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana30 分钟前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端
逍遥运德37 分钟前
前端工程化-03:包管理NPM-package.json 和 package-lock.json 详解
前端·前端框架·前端工程化
逗逗豆巴吧42 分钟前
WPS 加载项中实现当前文档直接上传
前端·javascript·ecmascript 6
慢功夫43 分钟前
💡【调试】按下 F5 后,mini-vscode 到底做了什么
前端·visual studio code
妙码生花1 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(二十一):网络请求封装优化
前端·javascript·vue.js