JavaScript手写异步加法asyncAdd方法详解_JavaScript

来源:脚本之家  责任编辑:小易  
目录
前言分析 asyncAdd直观的基本要求隐藏的考察点 — setTimeout & cb隐藏的考察点 — async & await实现 asyncAdd具体实现进行优化抽离内层函数缓存计算结果

前言

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

// 异步加法
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 可接收任意长度的参数sum 中只能通过 asyncAdd 实现加法计算sum 中需要处理异步逻辑,需要使用 Promise需要优化 sum 方法的计算时间

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

直观的基本要求

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

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

实现 sum 函数,即只能修改 sum 部分的内容不能直接使用加法(+),通过 asyncAdd 实现加法优化 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

具体实现

实现思路如下:

考虑到外部参数长度不固定,使用剩余运算符接收所有传入的参数考虑到 asyncAdd 中的异步操作,将其封装为 Promise 的实现,即 caculate 函数考虑到 asyncAdd 实际只能一次接收两个数字进行计算,使用循环的形式将多个参数分别传入考虑到通过循环处理异步操作的顺序问题,使用 async/await 来保证正确的执行顺序,且 async 函数的返回值正好符合 sumPromise 类型的要求

具体代码如下:

// 通过 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;
}

进行优化

抽离内层函数

caculate 函数可抽离到 sum 函数外层asyncAdd 函数的回调函数没必要抽离,因为它依赖的参数和外部方法太多
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手写异步加法asyncAdd方法详解的详细内容,更多关于JavaScript异步加法asyncAdd的资料请关注真格学网其它相关文章!

您可能感兴趣的文章:JavaScript?Generator异步过度的实现详解JS异步观察目标元素方式完成分页加载JavaScript事件循环同步任务与异步任务JavaScript异步队列进行try?catch时的问题解决JS异步的执行顺序分析Javascript处理循环的异步操作指南javascript实现一个数值加法函数

  • 本文相关:
  • 微信小程序实现锚点定位楼层跳跃的实例
  • 微信小程序日历组件calendar详解及实例
  • 超级强大的表单验证
  • google 地图类型详解及示例代码
  • 微信小程序 获取设备信息 api实例详解
  • 前端面试必会网络跨域问题解决方法
  • 微信小程序 生命周期和页面的生命周期详细介绍
  • 微信小程序 教程之wxapp视图容器 swiper
  • 微信小程序 wxapp视图容器 view详解
  • three.js实现雪糕地球的使用示例详解
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全javascriptasp.netphp编程ajax相关正则表达式asp编程jsp编程编程10000问css/htmlflex脚本加解密web2.0xml/rss网页编辑器相关技巧安全相关网页播放器其它综合dart首页javascriptjavascript?generator异步过度的实现详解js异步观察目标元素方式完成分页加载javascript事件循环同步任务与异步任务javascript异步队列进行try?catch时的问题解决js异步的执行顺序分析javascript处理循环的异步操作指南javascript实现一个数值加法函数微信小程序实现锚点定位楼层跳跃的实例微信小程序日历组件calendar详解及实例超级强大的表单验证google 地图类型详解及示例代码微信小程序 获取设备信息 api实例详解前端面试必会网络跨域问题解决方法微信小程序 生命周期和页面的生命周期详细介绍微信小程序 教程之wxapp视图容器 swiper微信小程序 wxapp视图容器 view详解three.js实现雪糕地球的使用示例详解微信小程序 数组(增,删,改,查)等操作实例详解微信小程序 for 循环详解微信小程序 小程序制作及动画(animation样式)详解微信小程序 input输入框控件详解及实例(多种示例)微信小程序 input输入框详解及简单实例微信小程序 传值取值的几种方法总结微信小程序 时间格式化(util.formattime(ne微信小程序中使元素占满整个屏幕高度实现方法微信小程序 wx.request(接口调用方式)详解及实例微信小程序通过api接口将json数据展现到小程序示例没有resolve及reject的promise是否会造成内存泄露微信小程序 buffer缓冲区的详解微信小程序 tab页切换更新数据微信小程序 地图map详解及简单实例js前端可扩展的低代码ui框架sunmao使用详解js处理数据实现分页功能js轻量级函数式编程实现xdm一微信小程序 数据访问实例详解微信小程序 绘图之饼图实现js 基本概念详细介绍
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved