前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端:如何处理AJAX请求的重复使用

前端:如何处理AJAX请求的重复使用

作者头像
小丑同学
发布2021-02-07 16:22:11
1.5K0
发布2021-02-07 16:22:11
举报
文章被收录于专栏:小丑的小屋小丑的小屋

作者|FloatFlower

翻译|小丑

在开发前端时,我们经常使用AJAX来初始化数据并动态渲染在页面上,但是在遇到一连串的相同数据都要进行请求时,就有可能对同一个API 发出并发请求,然而,因为这些请求是同时发出,因此响应也非常可能是相同的,这样讲可能不够清楚,直接写一个简易的范例来解释这个情况。

实际范例

首先我们先撰写一个API:

代码语言:javascript
复制
https://localhost:3000/api/v1/users/:uuid

这个API的回传值如下:

代码语言:javascript
复制
{
    "name":"Username{uuid}",
    "uuid":"{uuid}"
}

随后开一个Vue的demo,并且先通过Axios写一个请求的函数:

代码语言:javascript
复制
// fetch-user.js

const axios = require('axios');

module.exports = (uuid) => {
    let uri = `http://localhost:3000/users/${uuid}`;
    return new Promise(resolve => {
        axios.get(uri).then(resolve);
    })
};

然后我们在Vue例子中新增一个User Component(User.vue)来负责渲染并请求接口:

代码语言:javascript
复制
<template>
    <div v-if="init">
        <ul>
            <li>{{user.name}}</li>
            <li>{{user.uuid}}</li>
        </ul>
    </div>
</template>

<script>
    const fetchUser = require('../lib/fetch-user');
    export default {
        name: 'User',
        data: function() {
            return {
                init: false,
                user: null
            }
        },
        props: {
            uuid: String
        },
        async mounted() {
            const response = await fetchUser(this.uuid);
            this.init = true;
            this.user = response.data;
        }
    }
</script>

最后将用户组件放入App.vue中:

代码语言:javascript
复制
<template>
    <div id="app">
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
        <user uuid="user-uuid"></user>
    </div>
</template>

<script>
import User from './components/User';

export default {
    name: 'App',
    components: {
        User
    }
}
</script>
代码语言:javascript
复制
接着我们看一下显示结果:

这样就正确显示了,然而这里有一个问题非常值得注意:

我们打开开发者模式就会发现,每个组件向该API发出了请求,因此就产生了10次的并发请求,但是在这种情况下,实际上我们仅需要让一个请求出去,另外9个元件等待这个请求的响应然后重新使用即可。

改进的方法

接下来将讲解要如何实现关于在同一个组件之间唯一指定API请求一次并分配请求,我们会用到这个元件EventTarget,这个元件有点类似Node.js中的EventEmitter,主要就是用于接收事件。

随后我们改写fetchUser()函数:

代码语言:javascript
复制
const axios = require('axios');

/**
 * 这个 class 是用于存储 Response Data 的 Event 衍生类
 */
class FetchCompleteEvent extends Event {
    constructor(type, data) {
        super(type);
        this.data = data;
    }
}

// 用于请求成功时使用的事件监听器
const eventEmitter = new EventTarget();

// 用于请求失敗时使用的事件监听器
const errorEmitter = new EventTarget();

/**
 * 用于存储 URI 以及是否当前正在请求的状态,如:
 * http://localhost:8000/users/foo => true 代表已经发出请求,正在等待 Response
 * http://localhost:8000/users/bar => false 代表当前没有请求在路上
 */

const requestingList = new Map();

module.exports = (uuid) => {

    let uri = `http://localhost:3000/users/${uuid}`;

    return new Promise((resolve, reject) => {

        // 如果没有记录,或者尚未处于请求状态
        if (!requestingList.has(uri) || !requestingList.get(uri)) {

            // 进入之后立即将请求状态设为 true
            requestingList.set(uri, true);

            // 请求 URI
            axios.get(uri).then(response => {

                // 完成请求之后将请求状态设为 false
                requestingList.set(uri, false);

                // 发出一个事件通知來告诉 callback 请求完成了
                eventEmitter.dispatchEvent(new FetchCompleteEvent(uri, response));
                resolve(response);

            }).catch((e) => {

                // 请求失败也算是请求完成,将请求状态设为 false
                requestingList.set(uri, false);

                // 发出一个事件通知來告诉 callback 请求失败了
                errorEmitter.dispatchEvent(new FetchCompleteEvent(uri, e));
                reject(e);

            })
        }
         // 当目前指定的 URL 处于请求状态,则不做任何事情
        else {

            // 向成功的事件监听器注册,当完成之后 resolve()
            eventEmitter.addEventListener(uri, (event) => {
                resolve(event.data);
            });

            // 失败之后 reject()
            errorEmitter.addEventListener(uri, (event) => {
                reject(event.data);
            })
        }
    });
};

接着我们重新运行前端应用程序并查看结果:

结果与一开始一模一样,而是当时我们打开开发者模式就会发现:

请求已经被减少到剩下一个了,这是因为所有的元件都重复使用了一个同一个响应。通过这种方法将可以大大减少服务器的负载以及前端的运行时间。

总结

并非每一种情况下都可以使用这种方式来请求资源,如:每次请求资源都一定会发送不一样的API就不能使用这种方式进行API调用,但是像是上述范例中的用户资料,电商网站中的商品资料或文章等,类似能够确保在极短时间之内资源都是相同的API就可以使用这种方式来进行操作。

扩展阅读

https://dev.to/floatflower/ajax-414j

参考资料

1.https://developer.mozilla.org/zh-TW/docs/Web/API/EventTarget

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小丑的小屋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实际范例
  • 改进的方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档