Vue3.0异步调用数据时,数据顺序不一致问题

文章讲述了在开发过程中,作者遇到在Vue应用中根据用户ID从MySQL数据库获取歌曲推荐并按顺序展示的问题,通过使用async/await和for...of遍历来确保数据顺序一致性,最终解决了页面加载时数据不一致的问题。

在弄毕设的时候,要弄一个歌曲推荐页面,推荐歌曲已经通过Spark引擎已经处理好,存储在mysql数据库。现在要根据用户id,从数据库中选取推荐给该用户的全部歌曲id,再通过选出的歌曲id选出歌曲详细信息。

有了歌曲id列表后,需要遍历这个列表取出歌曲详细数据。

开始使用then来获取异步数据

if (store.getters.token) {
    // store.getters.username还要拿到username后,还得使用.value才能取出用户名称
    // 获取用户id
    const userId = computed(() => store.getters.userId);
    const songId = await HttpManager.getListSongRecommendOfSongId(userId.value);
    console.log("songId", songId);
    const index = ref(1);
    songId.data.forEach((item: any, index) => {
        console.log("songInfo", item.songId);
        HttpManager.getSongBaseOfId(item.songId).then( res => {
            console.log("res", res);
            res.data[0]["songName"] = getSongTitle(res.data[0].name);
            res.data[0]["singerName"] = getSingerName(res.data[0].name);
            res.data[0]["index"] = index;
            dataList.value.push(res.data[0]);
        })
    });
    console.log("dataList", dataList);

} else {
    // 推荐热榜前15首歌曲
    HttpManager.getSongTop().then((res) => {
        res.data.slice(0, 10).forEach((item: any, index) => {
            item["songName"] = getSongTitle(item.name);
            item["singerName"] = getSingerName(item.name);
            item["index"] = index;
            // list.push(item);
            dataList.value.push(item);
        });
        // dataList.value = list
    });
}

获取歌曲id的数据顺序还一致

const songId = await HttpManager.getListSongRecommendOfSongId(userId.value);

但通过歌曲id获取歌曲信息时,和songId里数据的顺序不一致,dataList第一条数据是M005891,和在songId里数据的顺序不一致

而且刷新页面后,这个dataListd的数据还会发生变化,这可能是异步调用的问题

接下来就解决这个数据顺序问题

使用foreach() + await来获取数据

开始使用then来获取数据,数据顺序会乱,所以先采用直接用foreach() + await来获取数据

// 用户登陆了才个性化推荐
if (store.getters.token) {
    // store.getters.username还要拿到username后,还得使用.value才能取出用户名称
    // 获取用户id
    const userId = computed(() => store.getters.userId);
    const songId = await HttpManager.getListSongRecommendOfSongId(userId.value);
    console.log("songId", songId);
    const index = ref(1);
    songId.data.forEach((item: any, index) => {
        console.log("songInfo", item.songId);
        const songInfo = await HttpManager.getSongBaseOfId(item.songId);
        console.log("songInfo", songInfo.data[0]);
        // console.log("songInfovalue", songInfo.data.value);
        songInfo.data[0]["songName"] = getSongTitle(songInfo.data[0].name);
        songInfo.data[0]["singerName"] = getSingerName(songInfo.data[0].name);
        songInfo.data[0]["index"] = index;
        dataList.value.push(songInfo.data[0]);
        index.value += 1
    });
    console.log("dataList", dataList);

} else {
    // 推荐热榜前15首歌曲
    HttpManager.getSongTop().then((res) => {
        res.data.slice(0, 10).forEach((item: any, index) => {
            item["songName"] = getSongTitle(item.name);
            item["singerName"] = getSingerName(item.name);
            item["index"] = index;
            // list.push(item);
            dataList.value.push(item);
        });
        // dataList.value = list
    });
}

 这句代码能够获取对应的歌曲id列表

const songId = await HttpManager.getListSongRecommendOfSongId(userId.value);

但下面的根据id获取歌曲信息的代码就报错了

songId.data.forEach((item: any, index) => {
        console.log("songInfo", item.songId);
        const songInfo = await HttpManager.getSongBaseOfId(item.songId);
        console.log("songInfo", songInfo.data[0]);
        // console.log("songInfovalue", songInfo.data.value);
        songInfo.data[0]["songName"] = getSongTitle(songInfo.data[0].name);
        songInfo.data[0]["singerName"] = getSingerName(songInfo.data[0].name);
        songInfo.data[0]["index"] = index;
        dataList.value.push(songInfo.data[0]);
        index.value += 1
    });

const songInfo = await HttpManager.getSongBaseOfId(item.songId);

使用for...of + await来获取数据

后面发现,使用for...of + await 这个语句可以运行,并且成功拿到数据

for (const item of songId.data) {
        console.log("songInfo", item.songId);
        const songInfo = await HttpManager.getSongBaseOfId(item.songId);
        console.log("songInfo", songInfo.data[0]);
        // console.log("songInfovalue", songInfo.data.value);
        songInfo.data[0]["songName"] = getSongTitle(songInfo.data[0].name);
        songInfo.data[0]["singerName"] = getSingerName(songInfo.data[0].name);
        songInfo.data[0]["index"] = index;
        dataList.value.push(songInfo.data[0]);
        index.value += 1
    }
    console.log("dataList", dataList);

没报错并且顺序是正确的,出现了个新问题,就是在页面上没显示。。。

使用for...of + await + async获取数据

后面又发现,await要和async一起使用,于是再外面套了一层async函数,通过这个函数的async,拿到数据后,也能在页面上显示了。这个函数只是套了一层,核心还是上面那些从数据库读数据的代码

// 获取推荐歌曲
const fetchData = async () => {
    try {
        // 用户登陆了才个性化推荐
        if (store.getters.token) {
            // store.getters.username还要拿到username后,还得使用.value才能取出用户名称
            // 获取用户id
            const userId = computed(() => store.getters.userId);
            const songId = await HttpManager.getListSongRecommendOfSongId(userId.value);
            console.log("songId", songId);
            const index = ref(1);
            for (const item of songId.data) {
                console.log("songInfo", item.songId);
                const songInfo = await HttpManager.getSongBaseOfId(item.songId);
                console.log("songInfo", songInfo.data[0]);
                // console.log("songInfovalue", songInfo.data.value);
                songInfo.data[0]["songName"] = getSongTitle(songInfo.data[0].name);
                songInfo.data[0]["singerName"] = getSingerName(songInfo.data[0].name);
                songInfo.data[0]["index"] = index;
                dataList.value.push(songInfo.data[0]);
                index.value += 1
            }
            console.log("dataList", dataList);

        } else {
            // 推荐热榜前15首歌曲
            HttpManager.getSongTop().then((res) => {
                res.data.slice(0, 10).forEach((item: any, index) => {
                    item["songName"] = getSongTitle(item.name);
                    item["singerName"] = getSingerName(item.name);
                    item["index"] = index;
                    // list.push(item);
                    dataList.value.push(item);
                });
                // dataList.value = list
            });
        }
    } catch (error) {
        console.error('Error fetching data:', error);
    }
};
fetchData()

然后,页面就有显示了,真是,这也能跑??

<think>好的,我现在需要帮助用户在Vue3.0项目中集成Zendesk。首先,我得回忆一下Zendesk通常的集成方式,可能包括嵌入脚本、使用API或者组件库。用户提到的是Vue3.0,所以我要考虑Vue3的特性,比如Composition API,还有如何正确管理生命周期钩子。第一步应该是引入Zendesk的脚本。通常,Zendesk会提供一个JavaScript代码片段,需要添加到HTML文件中。但Vue是单页面应用(SPA),直接修改public/index.html可能有效,但可能够灵活。或者,可以考虑动态加载脚本,避免重复加载,特别是在路由切换。接下来,可能需要初始化Zendesk的widget。在Vue组件中,应该在mounted生命周期钩子中初始化,确保DOM已经准备好。同,在beforeUnmount清理,防止内存泄漏。这里要注意Vue3的生命周期钩子名称是否有变化,比如beforeDestroy变成了beforeUnmount。另外,用户可能需要使用Zendesk的API,比如打开帮助中心或提交工单。这候需要检查window对象上是否成功加载了Zendesk的变量,比如zE或ZendeskAPI。可能需要添加类型声明,避免TypeScript报错,如果用户用的是TypeScript的话。 还有,如果用户需要更复杂的交互,比如在Vue组件中触发Zendesk功能,可能需要封装成自定义Hook或Composable函数,方便复用。例如,使用useZendesk这样的函数来管理初始化状态和API调用。 另外,响应式设计也是一个考虑点。比如,当用户登录状态变化,需要更新Zendesk的用户信息。这可以用watch或watchEffect来监听用户信息的变化,并调用Zendesk的identify方法。 可能遇到的问题包括脚本加载顺序导致的zE未定义,或者SPA路由切换widget重复加载。需要确保脚本只加载一次,并且在组件销毁正确移除事件监听器或widget实例。测试方面,建议用户在本地运行检查Zendesk是否正确加载,是否有控制台错误。可能需要处理异步加载脚本的情况,使用Promise或async/await来确保脚本加载完成后再执行初始化。最后,提供示例代码很重要,特别是如何在Vue组件中初始化和调用方法。同,注意事项部分要提醒用户替换占位符,比如subdomain和token,以及处理可能的CSP问题。</think>在Vue 3.0中集成Zendesk主要可通过以下三种方式实现: ### 一、基础脚本集成 1. 在`public/index.html`头部添加Zendesk脚本 ```html <script id="ze-snippet" src="https://static.zdassets.com/ekr/sdk.js" data-key="your-subdomain"></script> ``` 2.Vue组件中通过`window.zE`调用API ```javascript // 组件mounted生命周期 mounted() { window.zE(&#39;webWidget&#39;, &#39;show&#39;); } ``` ### 二、动态加载方案(推荐) ```javascript // utils/zendesk.js export function loadZendeskSdk(subdomain) { return new Promise((resolve) => { if (!window.zE) { const script = document.createElement(&#39;script&#39;); script.id = &#39;ze-snippet&#39;; script.src = `https://static.zdassets.com/ekr/sdk.js`; script.dataset.key = subdomain; document.head.appendChild(script); script.onload = resolve; } else { resolve(); } }); } ``` ### 三、Vue 3 Composition API封装 ```typescript // composables/useZendesk.ts import { onMounted, onUnmounted } from &#39;vue&#39;; export function useZendesk(config: { subdomain: string; widgetVisible?: boolean; }) { const initWidget = async () => { await loadZendeskSdk(config.subdomain); window.zE(&#39;webWidget&#39;, &#39;setLocale&#39;, &#39;zh-CN&#39;); window.zE(&#39;webWidget:on&#39;, &#39;close&#39;, () => { // 处理关闭事件 }); }; onMounted(() => { initWidget(); if (config.widgetVisible) { window.zE(&#39;webWidget&#39;, &#39;show&#39;); } }); onUnmounted(() => { window.zE(&#39;webWidget&#39;, &#39;close&#39;); }); return { openChat: () => window.zE(&#39;webWidget&#39;, &#39;open&#39;), setUser: (user: { email: string; name: string }) => { window.zE(&#39;webWidget&#39;, &#39;prefill&#39;, { email: user.email, name: user.name }); } }; } ``` ### 四、用户身份同步示例 ```javascript // 在用户登录后调用 watch(userStore.currentUser, (newUser) => { if (newUser) { window.zE(&#39;webWidget&#39;, &#39;identify&#39;, { email: newUser.email, name: newUser.name }); } }); ``` **注意事项**: 1. 需要处理SPA路由切换的widget状态[^1] 2. 建议在`.env`文件配置Zendesk参数: ```ini VITE_ZD_SUBDOMAIN=your-subdomain VITE_ZD_APP_ID=your-app-id ``` 3. 如果使用TypeScript,需添加类型声明: ```typescript declare global { interface Window { zE: (action: string, ...args: any[]) => void; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值