likes
comments
collection
share

throwing-functions二次封装注意点关于主题 至于标题中throwing-function: 如标题,这样

作者站长头像
站长
· 阅读数 20

throwing-functions二次封装注意点关于主题 至于标题中throwing-function: 如标题,这样

关于主题

至于标题中throwing-function:

“在js中,可能抛出错误的函数,有没有对应的专业术语来形容这样的函数?”

在JavaScript中,可能抛出错误的函数通常被称为“throwing functions”(抛出函数)。——ChatGPT

如标题,这样文章主题应该就比较明确了

背景

概述

写这篇文章的背景是,作者在个人项目中对一些原生api进行二次封装,然后在业务代码去调用封装好的方法,业务代码中妥善的写了错误处理的逻辑,可是当原生api抛出错误时,我们得到了控制台报错而非进行错误处理的逻辑,如Message提示等。换句话说业务代码中没有感知到二次封装方法的抛出错误。

错误代码示意

如下getMediaStream函数本质就是对navigator.mediaDevices.getUserMedia这个原生api进行二次封装,增加一些额外的逻辑

import to from 'await-to-js';
// 获取媒体流
export async function getMediaStream(constraints: MediaStreamConstraints = { video: true, audio: true }) {
  if (globalMediaStream) {
    return globalMediaStream;
  }
  const [error, stream] = await to(navigator.mediaDevices.getUserMedia(constraints));
  if (error) {
    return new Error('获取本地媒体失败, 请检查是否开启了摄像头与麦克风');
  }
  return (globalMediaStream = stream);
}

Plus:其中to函数是一个很简单的小工具,可以让异步逻辑嵌套更浅,简易源码如下:

function to(promise) {
  return promise
    .then(function (data) {
      return [null, data];
    })
    .catch(function (err) {
      return [err, undefined];
    });
}

我们在业务逻辑中使用getMediaStream如下:

const getMediaStreamConsumer = async () => {
  // ...
  const [err, stream] = await to(getMediaStream());
  if (err) {
    return ElMessage.error(err.message);
  }
  // ...other logic to use stream
}

分析

问题一、类型错误

首先经过如上封装,getMediaStream函数的返回值变成了MediaStream | Error,也就是原本navigator.mediaDevices.getUserMedia方法的返回值和Error的联合类型,这样我们在getMediaStreamConsumer函数中拿到stream去使用的时候还需要使用类型断言来排除Error干扰,如(stream as MediaStream).xxxFun()

问题二、to方法中失败的错误捕获

如果原生apinavigator.mediaDevices.getUserMedia执行报错,那么我们希望getMediaStreamConsumer中可以从to方法的返回值中解构得到err,进而触发ElMessage.error的错误提示,但是事实是err的值永远为undefined

原因就在于我们二次封装throwing functions时没有保持它原来的返回值类型,无论是Error类型还是什么类型,getMediaStream函数永远拥有返回值,自然消费它的函数永远拿不到err,换句话说getMediaStreamConsumer里的to方法的执行过程中,没有错误被抛出。

解决方法

二次封装throwing functions时使用throw抛出错误来保持原api的特点,而不是return

如下

import to from 'await-to-js';
export async function getMediaStream(constraints: MediaStreamConstraints = { video: true, audio: true }) {
  if (globalMediaStream) {
    return globalMediaStream;
  }
  const [error, stream] = await to(navigator.mediaDevices.getUserMedia(constraints));
  if (error) {
    // 抛出错误
    throw new Error('获取本地媒体失败, 请检查是否开启了摄像头与麦克风');
  }
  return (globalMediaStream = stream);
}
转载自:https://juejin.cn/post/7371698970975256603
评论
请登录