• 技术文章 >web前端 >js教程

    JavaScript介绍之手写异步加法asyncAdd方法

    WBOYWBOY2022-08-26 14:04:13转载678
    本篇文章给大家带来了关于javascript的相关知识,其中主要为大家介绍了JavaScript手写异步加法asyncAdd方法详解,有需要的朋友可以借鉴参考下,下面一起来看一下,希望对大家有帮助。

    大前端成长进阶课程:进入学习

    【相关推荐:javascript视频教程web前端

    前言

    在掘金上发现一道既简单但个人觉得还挺有意思的一道题,题目如下:

    // 异步加法
    function asyncAdd(a,b,cb){
      setTimeout(() => {
        cb(null, a + b)
      }, Math.random() * 1000)
    }
    async function total(){
      const res1 = await sum(1,2,3,4,5,6,4)
      const res2 = await sum(1,2,3,4,5,6,4)
      return [res1, res2]
    }
    total()
    // 实现下 sum 函数。注意不能使用加法,在 sum 中借助 asyncAdd 完成加法。尽可能的优化这个方法的时间。
    function sum(){
    }

    你可以直接尝试实现下,考察下自己的思维和 JavaScript 基础知识的联系如何,大佬请绕行!

    估计大多数人第一眼看下都不知道这题目到底要干啥(我不说就没人知道我也是),但是在看第二遍的时候估计就差不多明白具体是要考察什么内容了,下面就一起来分析分析吧!!!

    分析 asyncAdd

    这里先放置最终结论:

    下面是分别通过对代码的不同部分进行分析,获取到的相关的信息。

    直观的基本要求

    // 实现下 sum 函数。注意不能使用加法,在 sum 中借助 asyncAdd 完成加法。尽可能的优化这个方法的时间。 
    function sum(){ }

    最直观的方式就是通过上述的文字描述部分,可以很容易知道题目具体要求:

    隐藏的考察点 — setTimeout & cb

    // 异步加法
    function asyncAdd(a, b, cb){
      setTimeout(() => {
        cb(null, a + b)
      }, Math.random() * 1000)
    }

    从上述内容来看,最明显的就是 setTimeoutcb 了,其实这不难理解因为在 asyncAdd 中使用了 setTimeout 只能通过回调函数 cb 将本次计算结果返回出去,那其中的第一个参数 null 代表什么呢?

    其实可以认为它是一个错误信息对象,如果你比较了解 node 的话,就会知道在 node 中的异步处理的回调函数通常第一个参数就是错误对象,用于传递给外部在发生错误时自定义后续执行逻辑等。

    一句话: cb 函数会接收 错误对象 和 计算结果 作为参数传递给外部。

    隐藏的考察点 — async & await

    async function total(){
      const res1 = await sum(1,2,3,4,5,6,4)
      const res2 = await sum(1,2,3,4,5,6,4)
      return [res1, res2]
    }

    从上述的这部分来看,sum 方法的 返回值 肯定是一个 promise 类型的,因为最前面明显的使用了 await sum(...) 的形式。

    另外 total 函数返回值也必然是一个 promise 类型,因为整个 total 函数被定义为了一个 async 异步函数,可点击此处查看详细内容。

    一句话:sum 需要返回 promise 类型的值,即 sum 一定会使用到 promise,并且从 sum(1,2,3,4,5,6,4) 可知 sum 可接收任意长度的参数。

    实现 asyncAdd

    具体实现

    实现思路如下:

    具体代码如下:

    // 通过 ES6 的剩余运算符(...) 接收外部传入长度不固定的参数
    async function sum(...nums: number[]) {
        // 封装 Promise 
        function caculate(num1: number, num2: number) {
            return new Promise((resolve, reject) => {
                // 调用 asyncAdd 实现加法
                asyncAdd(num1, num2, (err: any, rs: number) => {
                    // 处理错误逻辑
                    if (err) {
                        reject(err);
                        return;
                    }
                    // 向外部传递对应的计算结果
                    resolve(rs);
                });
            })
        }
        let res: any = 0;
        // 通过遍历将参数一个个进行计算
        for (const n of nums) {
            // 为了避免异步执行顺序问题,使用 await 等待执行结果 
            res = await caculate(res, n);
        }
        return res;
    }

    进行优化

    抽离内层函数

    function caculate(num1: number, num2: number) {
        return new Promise((resolve, reject) => {
            asyncAdd(num1, num2, (err: any, rs: number) => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(rs);
            });
        })
    }
    async function sum(...nums: number[]) {
        let res: any = 0;
        for (const n of nums) {
            res = await caculate(res, n);
        }
        return res;
    }

    缓存计算结果

    其实你仔细观察 total 方法,其中 sum 调用了两次,而且参数还是一模一样的,目的就是提示你在第二次计算相同内容时结果直接 从缓存中获取,而不是在通过异步计算。

    async function total(){
      const res1 = await sum(1,2,3,4,5,6,4)
      const res2 = await sum(1,2,3,4,5,6,4)
      return [res1, res2]
    }

    以下只是一个简单的缓存方案的实现,不必过于纠结,具体实现如下:

    const cash: any = {};
    function isUndefined(target: any) {
        return target === void 0;
    }
    async function sum(...nums: number[]) {
        let res: any = 0;
        const key = nums.join('+');
        if (!isUndefined(cash[key])) return cash[key];
        for (const n of nums) {
            res = await caculate(res, n);
        }
        cash[key] = res;
        return res;
    }
    function caculate(num1: number, num2: number) {
        return new Promise((resolve, reject) => {
            asyncAdd(num1, num2, (err: any, rs: number) => {
                if (err) {
                    reject(err);
                    return;
                }
                resolve(rs);
            });
        })
    }

    【相关推荐:javascript视频教程web前端

    以上就是JavaScript介绍之手写异步加法asyncAdd方法的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:脚本之家,如有侵犯,请联系admin@php.cn删除

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:javascript
    上一篇:【整理分享】阿里巴巴的15个顶级前端开源项目,看看你都用过哪些! 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• JavaScript学习之使用const声明常量• JavaScript ECMAScript 6所有新特性总结• JavaScript中异步与回调的基本概念及回调地狱现象• JavaScript复制页面内容的三种方案(总结分享)• JavaScript前端迭代器Iterator与生成器Generator讲解
    1/1

    PHP中文网