场景题-请求合并 | 刷题打卡

简介: 面试中常考的一个代码题,也是业务开发中经常会遇到的问题

题目描述


短时间内需要请求多个同类型的资源

期望多个请求合并成一个请求发送


例如:

  • 有一个接口其请求路径为 /path
  • query有一个id参数支持传一个或者多个id
  • /path?id=1
  • /path?id=1,2,3
  • 对应的响应格式为


{
    code:0,
    data:{
        1:{},
    },
    errMsg:'success'
}
// or
{
    code:0,
    data:{
        1:{},
        2:{},
        3:{}
    },
    errMsg:'success'
}


request 方法示例


request({
    url:'/path',
    query:{
        id: '0'
    }
})


要求


实现一个 getArticle 方法,每个方法回调最终拿到的是自己需要的内容,且短时间内只发出了一次请求


getArticle(3).then(res=>{})
getArticle(4).then(res=>{})
getArticle(5).then(res=>{})
getArticle(6).then(res=>{})
// request({
//     url:'/path',
//     query:{
//         id:'3,4,5,6'
//     }
// })


题目分析


场景分析


常见需要短时间请求多个同类型资源的场景就是资源懒加载的时候

  • 如:一个文章列表的中,获取每个展示文章点赞/评论数是单独的一个接口
  • 当一次性需要展示多条新闻,那么就要发起多个查询点赞/评论的请求

后端为了减少处理请求的压力,通常会让一个接口支持同时查询多条数据的能力


考点


  1. 怎么确定这个短时间是多久?
  • 其实这里就是考察到了event loop,这个短时间就是指同一个周期内,然后就变成了合并同一个周期内的请求,如何保证在一个周期内,这里就可以用到防抖,让请求在执行宏任务的时候发出
  1. 如何让每个方法拿到自己需要的数据?
  • 这里可以在方法内部用一个map将每个方法的Promise的resolve存起来,每个方法传参的id作为key,在接口响应后,将对应数据通过key取出,然后从map中取出对应Promise的resolve然后执行resolve(data[id])即可


需要考虑的问题


  1. 如果多个请求参数是一样的那么,最终请求的参数只有一个
  • 如 连续调用两次 getArticle(3)
  • 那么 请求的query依旧是 {id:'3'}而不是 {id:'3,3'}
  • 并且这两个请求的方法都需要得到响应
  1. 如果这个请求没有被按时响应,不能影响下一次发送


代码实现


var getArticle = (function () {
    let timer = null;
    let resolveMap = new Map();
    return function (id) {
        return new Promise((resolve) => {
            // 这里用string类型作为key
            const key = `${id}`;
            const resolves = resolveMap.get(key);
            // 不存在则创建,因为可能有重复的id,所以这里value为数组
            if (!resolves) {
                resolveMap.set(key, [resolve]);
            } else {
                // 存在则加入,因为是对象,map里存的引用,所以这里不需要重新执行set
                resolves.push(resolve)
            }
            if (timer) {
                clearTimeout(timer)
            }
            timer = setTimeout(() => {
                // 这里将把请求发出去,需要重置状态
                // 所以将现有的保存下来
                const _resolvesMap = resolveMap
                const keys = [..._resolvesMap.keys()]
                request({
                    url: '/path',
                    query: keys.join(',')
                }).then(res => {
                    const { data } = res
                    // 执行resolve
                    for (const key of keys) {
                        const resolves = _resolvesMap.get(key)
                        const v = data[key]
                        resolves.forEach(r => r(v))
                    }
                })
                // 请求发出后就初始化,以便用于下次请求
                timer = null;
                resolveMap = new Map();
            })
        });
    };
})();


测试


模拟实现一个request


function request(options = {}) {
    console.log(new Date(), '发起一次请求', '-------参数为:', options.query)
    return new Promise(res => {
        const { query } = options
        if (!query) {
            res({ data: {} })
            return
        }
        const ids = query.split(',')
        const testData = ids.reduce((pre, id) => {
            pre[id] = {
                id,
                rand: Math.random()
            }
            return pre
        }, {})
        // 模拟响应延迟
        setTimeout(() => {
            res({
                code: 0,
                data: testData,
                errMsg: 'ok'
            })
        }, 500)
    })
}


测试用例


getArticle(1).then(console.log)
getArticle(3).then(console.log)
getArticle(2).then(console.log)
getArticle(2).then(console.log)
getArticle(1).then(console.log)
new Promise((res) => {
    getArticle(4).then(console.log)
    res()
})
setTimeout(() => {
    getArticle(1).then(console.log)
    getArticle(3).then(console.log)
    getArticle(2).then(console.log)
    getArticle(2).then(console.log)
    getArticle(1).then(console.log)
}, 400)


打印结果


网络异常,图片无法展示
|


总结


  1. 考察知识点 event loop,防抖,Promise
  2. 这是一个很常见的业务问题,考察面试者的动手实践能力


代码仅供参考,如有考虑不周之处,还请斧正


相关文章
|
10天前
|
算法
【❤️算法笔记❤️】-每日一刷-23、合并 K 个升序链表
【❤️算法笔记❤️】-每日一刷-23、合并 K 个升序链表
25 0
|
5月前
|
存储 算法 前端开发
前端算法-合并两个有序数组
前端算法-合并两个有序数组
|
10月前
|
存储 算法 前端开发
前端算法专栏-数组-88.合并两个有序数组
前端算法专栏-数组-88.合并两个有序数组
每日一题——最近的请求次数
每日一题——最近的请求次数
80 0
每日一题——最近的请求次数
LeetCode每日一题(18)——最近的请求次数
最近的请求次数 1.题目 2.示例 3.思路 4.代码
多个so合并为一个so的思路
多个so合并为一个so的思路
323 0
|
算法 C++
【牛客刷题-算法】加精 | 合并两个有序的链表 - 从思路设计、bug排除到最终实现的全过程
【牛客刷题-算法】加精 | 合并两个有序的链表 - 从思路设计、bug排除到最终实现的全过程
116 0
【牛客刷题-算法】加精 | 合并两个有序的链表 - 从思路设计、bug排除到最终实现的全过程
|
缓存 NoSQL 算法
这么秀的操作我竟然到现在才了解到?合并请求~
在几年前,我就看到过有些博客写关于合并请求的文章,一开始我没有太在意,最近在看一个up讲述关于商品模块的牛X设计,为了提高高并发的处理能力,一般会用redis 自增自减来实现库存扣减,但是他采用合并扣减库存,也就是同一时间n个扣减库存会合并成一个请求,这样无疑减少了IO次数,也提高系统性能
281 1
这么秀的操作我竟然到现在才了解到?合并请求~
【刷题记录】21. 合并两个有序链表
【刷题记录】21. 合并两个有序链表
150 0
【刷题记录】21. 合并两个有序链表