无法设置地图异步

时间:2018-01-23 20:56:21

标签: node.js amazon-s3 youtube-api

我试图从s3中读取一个文件,该文件存储艺术家的名字并在youtube上获得前10首歌曲。

我能够获取s3数据,并且能够使用youtube数据api获得数据 我想将数据存储在我创建的对象数组中,这些对象称为歌手。

console.log("Loading up the best code ever!!!");

var fs = require('fs');
// Load the SDK for JavaScript
var AWS = require('aws-sdk');
var jsonfile = require('jsonfile')
var Singer = require('./Singer')
// Set the region 
AWS.config.update({ region: "us-west-1" });
var credentials = new AWS.SharedIniFileCredentials();
AWS.config.credentials = credentials;
// Create S3 service object
s3 = new AWS.S3({ apiVersion: '2006-03-01' });
console.log("after S3");


// Create the parameters for calling createBucket
var bucketParams = {
    Bucket: 'pc-backend-exercises',
    Key: 'toSearch.json',
    ResponseContentType: 'application/json'
};

/// youtube part
var YTAPI = require('node-youtubeapi-simplifier');

var APIKEY = 'kekekek' 

YTAPI.setup(APIKEY);

var singers = [];
var print = function printJson() {

    console.log('entered printJson')
    console.log(singers);
    var results = {}
    for (var i = 0; i < singers.length; i++) {
        results[singers[i].name] = singers[i];

    }
    JSON.stringify(results);
    console.log(results);
}


s3.getObject(bucketParams, function (err, data) {
    // Handle any error and exit
    console.log('download json file from s3');
    if (err) {
        console.log(err, err.stack);
        return err;
    }
    var fileContents = data.Body.toString();
    var json = JSON.parse(fileContents);

    for (var i = 0; i < json.Search.artists.length; i++) {
        var newSinger = new Singer(json.Search.artists[i]);
        singers.push(newSinger);
    }

    search10TopForASinger(print);

});

function search10TopForASinger(print) {
    console.log('entered search10TopForASinger ')
    for (var i = 0; i < singers.length; i++) {
        //Gets only 10 results
        var songsMap = singers[i].songs;
        YTAPI.searchFunctions.simpleSearch(singers[i].name).then(
            function (data) {
                setMap(data,songsMap);
            });
    }
    print();
}

function setMap(data, songs) {
    console.log('entered setMap')
    var size = 10;
    if (data.length < 10) {
        size = data.length;
    }

    for (var i = 0; i < size; i++) {
       songs.set(i, data[i].title);
    }
    console.log(songs);
}

我做了一些更改并取得了更好的效果:

Loading up the best code ever!!!
after S3
download json file from s3
entered search10TopForASinger
entered printJson
[ Singer { name: 'Katy', songs: Map {} },
  Singer { name: 'Madonna', songs: Map {} },
  Singer { name: 'Rihanna', songs: Map {} },
  Singer { name: 'Beyonce', songs: Map {} } ]
{ Katy: Singer { name: 'Katy', songs: Map {} },
  Madonna: Singer { name: 'Madonna', songs: Map {} },
  Rihanna: Singer { name: 'Rihanna', songs: Map {} },
  Beyonce: Singer { name: 'Beyonce', songs: Map {} } }
entered setMap
Map {
  0 => 'Madonna\'s Greatest Hits',
  1 => 'Madonna - Bitch I\'m Madonna ft. Nicki Minaj',
  2 => 'Madonna - La Isla Bonita (Official Music Video)',
  3 => 'Madonna - Hung Up (Official Music Video)',
  4 => 'madonna',
  5 => 'Madonna - Like A Prayer (Official Music Video)',
  6 => 'Madonna - Hollywood (Official Music Video)',
  7 => 'Madonna - Vogue (video)',
  8 => 'Madonna - Get Stupid (Studio version)',
  9 => 'Madonna - The Power Of Good-Bye' }
entered setMap
Map {
  0 => 'KatyPerryVEVO',
  1 => 'Katy Perry - Hey Hey Hey (Official)',
  2 => 'Katy Perry - Swish Swish (Official) ft. Nicki Minaj',
  3 => 'Katy Perry - Bon Appétit (Official) ft. Migos',
  4 => 'Katy Perry - Chained To The Rhythm (Official) ft. Skip Marley',
  5 => 'Katy Perry - Dark Horse (Official) ft. Juicy J',
  6 => 'LustreLux',
  7 => 'Katy Perry - The One That Got Away (Official)',
  8 => 'Katy Perry - Roar (Official)',
  9 => 'Katy Perry - Wide Awake (Official)' }
entered setMap
Map {
  0 => 'DJ Khaled - Wild Thoughts ft. Rihanna, Bryson Tiller',
  1 => 'Rihanna Greatest Hits ---- Rihanna Best Song New 2017',
  2 => 'N.E.R.D & Rihanna - Lemon',
  3 => 'RihannaVEVO',
  4 => 'Rihanna - Diamonds',
  5 => 'Rihanna - Work (Explicit) ft. Drake',
  6 => 'Kendrick Lamar - LOYALTY. ft. Rihanna',
  7 => 'Rihanna - Man Down',
  8 => 'Rihanna - Stay ft. Mikky Ekko',
  9 => 'Calvin Harris - This Is What You Came For (Official Video) ft. Rihanna' }
entered setMap
Map {
  0 => 'beyonceVEVO',
  1 => 'Beyoncé - Hold Up (Video)',
  2 => 'Beyoncé - Formation',
  3 => 'Beyoncé - Halo',
  4 => 'Ed Sheeran - Perfect Duet (with Beyoncé) [Official Audio]',
  5 => 'Beyoncé - Love On Top (Video Edit)',
  6 => 'Beyoncé - 7/11',
  7 => 'Beyoncé - Sorry (Video)',
  8 => 'Beyoncé - Drunk in Love (Explicit) ft. JAY Z',
  9 => 'J Balvin, Willy William - Mi Gente ft. Beyoncé' }

所以代码正常工作,我确实找到了每位歌手的10首歌曲,但是当我去printJson函数时,歌曲地图是空的

1 个答案:

答案 0 :(得分:1)

请记住,同步代码不会等待异步代码解析。它将触发异步功能,然后立即转到下一行。所以在这个函数中:

function search10TopForASinger(print) {
    console.log('entered search10TopForASinger ')
    for (var i = 0; i < singers.length; i++) {
        //Gets only 10 results
        var songsMap = singers[i].songs;
        YTAPI.searchFunctions.simpleSearch(singers[i].name).then(
            function (data) {
                setMap(data,songsMap);
            });
    }
    print();
}

您的for循环将会启动,触发每个simpleSearch来电,然后会调用print然后搜索将开始解析。

你可以通过链接一堆.then调用,或者通过编写迭代遍历所有内容并将其自身称为回调的递归函数来解决这个问题。最简单的方法是利用Promise.all。只需将for循环替换为:

function search10TopForASinger(print) {
    Promise.all(singers.map(function(singer) {
        var songsMap = singer.songs;
        return YTAPI
            .searchFunctions
            .simpleSearch(singer.name)
            .then(function(data) {
                setMap(data, songsMap)
            })
    })).then(function(results) {
        print()
    })
}

Promise.all接受一系列Promises,这是singers.map将返回的内容。它将返回一个promise本身,它只会在数组中的每个promise都解析后才会解析。

如果您正在运行节点8,您还可以使用await,这将在没有重构的情况下工作:

async function search10TopForASinger(print) {
    for (var i = 0; i < singers.length; i++) {
        var songsMap = singers[i].songs;
        var data = await YTAPI.searchFunctions.simpleSearch(singers[i].name);
        setMap(data, songsMap);
    }
    print();
}

这基本上会在后台创建一个.then链,因此该函数的每一部分都会等到await结算继续。请记住,您必须将search10TopForASinger转换为异步函数才能使其正常工作。