【问题标题】:Problem with Node JS and promises return before finishNode JS 的问题和承诺在完成前返回
【发布时间】:2020-05-17 10:03:03
【问题描述】:

我尝试获取带有统计信息的 Youtube 特定频道 ID 的最后上传视频列表。我得到了列表,但没有得到统计数据。

我认为结果是在对象分配之前返回的。对象赋值后如何返回结果?

这是我的代码:

async function (inputs, exits) {

    var { google } = require('googleapis');
    var youtubeApiKey = 'API_KEY';
    var service = google.youtube('v3');

    // Get upload ID to list uploaded videos
    service.channels.list({
        part: 'contentDetails',
        id: inputs.ytbIdChannel,
        key: youtubeApiKey,
    })
        .then(res => {
            if (res.data.items[0].contentDetails.relatedPlaylists.uploads) {
                let uploadsId = res.data.items[0].contentDetails.relatedPlaylists.uploads;

                // With the uploadID, get all uploaded videos
                service.playlistItems.list({
                    part: 'snippet',
                    playlistId: uploadsId,
                    maxResults: '12',
                    key: youtubeApiKey,
                })
                    .then(res => {
                        this.youtbeVideos = res.data.items,

                        // For each videos in list, inject the statistics object and return all videos
                        this.youtbeVideos.forEach(video => {
                            let videoId = video.snippet.resourceId.videoId

                            service.videos.list({
                                part: 'statistics',
                                id: videoId,
                                key: youtubeApiKey,
                            })
                                .then(res => {
                                    Object.assign(video, res.data.items[0].statistics)
                                    return exits.success(
                                        this.youtbeVideos
                                    );
                                })
                                .catch(error => {
                                    console.error(error);
                                });
                        });



                    })
                    .catch(error => {
                        console.error(error);
                    });
            }
        })
        .catch(error => {
            console.error(error);
        });

}

感谢您的帮助

【问题讨论】:

    标签: node.js promise youtube-api


    【解决方案1】:

    也许您可以将 .then 更改为 async/await。

    例如:

    service.getAll()
      .then(res => {
          service.getById(res.id)
            .then(res =>{
               .....
           })
        })
    

    你可以使用等待:

    const res1 = await service.getAll();
    const res2 = await service.getById(res1.id);
    

    这是更干净的代码,并且使用 await,节点停止所有步骤并等待它。完成后,将进入下一步......然后再次......等待,执行,等待,执行。

    【讨论】:

      【解决方案2】:

      您可能应该返回或“等待”承诺。不只是打电话给他们。 否则没人知道函数什么时候准备好。

      在每个service.XXX.list 之前写await,使你的回调函数async 并使用for looppromise.all 而不是forEach 用于this.videos,否则你不能等待每一个承诺(await within forEach )

      也许这是要解决的问题:

      • 您为每个视频调用return exits.success(this.youtbeVideos);,不应该为所有视频完成吗?
      • Object.assign(video, res.data.items[0].statistics) 可能每次都分配相同的键(覆盖)

      免责声明:我不知道 api/你的调用环境,所以这只是建议,也许会有用。

      【讨论】:

        【解决方案3】:

        我已修复您的代码并验证它可以与 YouTube API 一起使用。

        首先,通过替换来创建一个异步函数:

        service.channels.list({
            part: 'contentDetails',
            id: inputs.ytbIdChannel,
            key: youtubeApiKey,
        })
            .then(res => {
        

        与:

        service.channels.list({
            part: 'contentDetails',
            id: inputs.ytbIdChannel,
            key: youtubeApiKey,
        })
            .then(async res => {
        

        然后,为了更正,您需要用以下代码替换 if (res.data.items[0].contentDetails.relatedPlaylists.uploads) 块的内容:

        let uploadsId = channels.data.items[0].contentDetails.relatedPlaylists.uploads;
        
        // With the uploadID, get all uploaded videos
        let videos = await service.playlistItems.list({
            part: 'snippet',
            playlistId: uploadsId,
            maxResults: '12',
            key: youtubeApiKey,
        })
        this.youtbeVideos = videos.data.items;
        
        // For each videos in list, inject the statistics object and return all videos
        for (let video of this.youtbeVideos) {
            let videoId = video.snippet.resourceId.videoId
        
            let stats = await service.videos.list({
                part: 'statistics',
                id: videoId,
                key: youtubeApiKey,
            })
            Object.assign(video, stats.data.items[0].statistics)
        }
        
        return exits.success(
            this.youtbeVideos
        );
        

        我所做的两个关键更改是:

        1. 使用await 使this.youtbeVideos 上的迭代暂停,以便在继续之前检索统计信息
        2. 将返回和调用移到循环外exits.success,以便在添加所有统计信息后返回数据一次

        您可以在此处在线run my working copy - 只需为 YouTube 添加您的 API 密钥。

        当列表返回时,它将包含预期的所有统计信息。

        【讨论】:

        • 欢迎您 :) 我很高兴现在一切都为您工作
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-13
        • 1970-01-01
        • 2019-05-29
        • 2022-01-26
        • 2020-07-08
        相关资源
        最近更新 更多