面试官桀桀一笑:请手写一个Promise.all(判断是不是Promise、js抛出错误)

前言

  • 本文如标题,回顾三个知识点
  • 判断是不是Promise
  • js抛出错误的类型
  • 手写Promise.all

判断是不是Promise

方式一 Object.prototype.toString.call

代码如下:

js 复制代码
// p存在,且对象原型上是Promise
function isPromise(p) {
    return p && Object.prototype.toString.call(p) === "[object Promise]";
}

方式二 Promise有.then方法,以此为依据

代码如下:

js 复制代码
// 有值,且值是对象或函数,在一个也要有.then的函数方法
function isPromise(val) {
    return (
        val &&
        (typeof val === 'object' || typeof val === 'function') &&
        typeof val.then === 'function'
    );
}

二者对比

  • 方式二比方式一更为精准强大(推荐)
  • 对于规范化的Promise(就是JavaScript自带的Promise)
  • 二者判断检测结果能力都一样
  • 但是对于一些特定的Promise可能不太准确
  • 比如:特定库的Promise(Tiny Promise)、或者自己继承Promise去操作什么的,可能不太够用
  • 不过正常来说也够用了

js如何抛出错误?

  • 在js中抛错是通过throw语句,进一步来说,又可以分为:
  • 直接抛
  • 进阶抛

直接抛错误

throw语句后面抛什么都行,比如:

js 复制代码
    // 抛出各种数据类型
    throw '报错了' 

    throw 404

    throw false

    throw null

    throw undefined

    throw {}

    throw () => {}

    throw []

一般来说,抛出字符串比较多一些,不会抛出各种其他的数据类型

进阶抛错误

  • 如果想要进一步明确错误的类型
  • 可以使用js自带的Error相关构造函数
  • 一般常见的有4个如下:
js 复制代码
// 常见的4种进阶错误区分
throw new Error('普通错误') // 抛出普通错误(用的多一些)

throw new SyntaxError('语法错误') // 抛出语法错误

throw new ReferenceError('引用错误') // 抛出引用错误

throw new RangeError('范围错误') // 抛出范围错误

工作中我们根据具体的情况和需求,选择合适的方式来抛出错误能处理异常更加"优雅"

手写一个Promise.all

复制粘贴即用,注释代码:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.0/axios.js"></script>
</head>

<body>
    <script>
        // 判断是不是Promise
        function isPromise(p) {
            return p && Object.prototype.toString.call(p) === "[object Promise]";
        }

        function myPromiseAll(promises) {
            return new Promise((resolve, reject) => {
                if (!Array.isArray(promises)) {
                    throw new TypeError('接收的必须是数组,不是数组抛错');
                }
                if (promises.length === 0) {
                    throw new Error('接收的数组不能为空,空数组也抛错');
                }
                // Promise.all接收数组,最终也返回数组,result存起来用于返回
                const result = [];
                // 已经完成的数量,初始为0
                let doneNum = 0;
                // 数组循环执行
                promises.forEach((promise, index) => {
                    if (!isPromise(promise)) { throw new TypeError('接收的数组中的每一项都必须要是Promise') }
                    promise
                        .then((val) => {
                            result[index] = val; // 顺序存值
                            // result.push(val); // 非顺序存值
                            doneNum = doneNum + 1; // 已完成数量+1
                            if (doneNum === promises.length) { resolve(result) } // 任务全部完成,resolve出去
                        })
                        .catch((err) => {
                            // 只要有一个Promise失败,立刻拒绝返回Promise
                            reject(err);
                        })
                });
            });
        }

        const p1 = function () {
            return new Promise(async (resolve, reject) => {
                let res = await axios.get('http://ashuai.work/api/getIdName?id=1')
                resolve(res)
            })
        }
        const p2 = function () {
            return new Promise(async (resolve, reject) => {
                let res = await axios.get('http://ashuai.work/api/getIdName?id=2')
                resolve(res)
            })
        }
        const p3 = function () {
            return new Promise(async (resolve, reject) => {
                let res = await axios.get('http://ashuai.work/api/getIdName?id=3')
                resolve(res)
            })
        }

        myPromiseAll([p1(), p2(), p3()])
            .then((values) => { console.log(values) })
            .catch((error) => { console.error(error) })

    </script>
</body>

</html>

手写Promise... 未完待续...

相关推荐
Best_Liu~2 小时前
el-table实现固定列,及解决固定列导致部分滚动条无法拖动的问题
前端·javascript·vue.js
苏十八4 小时前
前端进阶:Vue.js
前端·javascript·vue.js·前端框架·npm·node.js·ecmascript
乐容5 小时前
vue3使用pinia中的actions,需要调用接口的话
前端·javascript·vue.js
似水明俊德5 小时前
ASP.NET Core Blazor 5:Blazor表单和数据
java·前端·javascript·html·asp.net
friklogff7 小时前
【JavaScript脚本宇宙】美化网格布局:Isotope和Masonry让你的网页焕然一新
开发语言·前端·javascript
程楠楠&M8 小时前
vue3.0(十六)axios详解以及完整封装方法
前端·javascript·vue.js·axios·anti-design-vue
朝思暮柒11 小时前
顶顶通呼叫中心中间件-外呼通道变量同步到坐席通道变量(mod_cti基于Freeswitch)
开发语言·javascript·ecmascript
清橙200011 小时前
Vite配置环境变量以及动态更新html数据
开发语言·javascript·safari
st紫月11 小时前
用MySQL+node+vue做一个学生信息管理系统(二):创建MySQL数据表、创建HTML用户列表页面
javascript·vue.js·mysql
睿智的海鸥11 小时前
html+JavaScript+css 24点计算器
前端·javascript·css·算法·html