繁体   English   中英

代码在里面。然后在Promise之前执行

[英]Code inside .then executing before the Promise

我有来自Spotify的JSON文件,其中包含代表艺术家的对象。 在这些对象中,其中一个属性是'genres',它是一个字符串数组(流派)。

我想要做的是在MongoDB中查找或创建这些类型。 然后将这些对象ID添加到数组中,并在创建Artist对象时传递该数组。

但是,我的艺术家在找到或创建他们的流派的过程之前就以DB方式创建了。

因此,行fillRest在fillGenres之前运行。

我试过从Object.values.forEach更改为for..of,for..in,不同的asyncs,promises,调制代码......

基本上添加等待我可以到处(大多数在错误的地方)

import * as data from '../spotify_data/artist_id.json';

async function fillGenres(array) {
  const genreIDs = []; // array of genre object IDs I'm trying to put inside every appropriate artist

  if (array !== 'undefined') {
    for (const element of array) {
      await Genre.findOrCreate({ name: element }, (err, result) => {
        genreIDs.push(result._id);
      });
    }
  }

  return genreIDs;
}

async function fillRest(entry, genreIDs) {
  const artist = {
    name: entry.ArtistName,
    genres: genreIDs,
    spotifyID: entry.ArtistID,
    popularity: entry.Popularity,
    spotifyFollowers: entry.Followers,
  };

  Artist.create([artist])
    .then((result) => {
      console.log(result);
    })
    .catch((error) => {
      console.log(error);
    });
}

async function spotifySeed() {
  const entries = Object.values(data);

  for (const entry of entries) {
     fillGenres(entry.Genres)
        .then((genreIDs) => {
          fillRest(entry, genreIDs); // this line gets executed before fillGenres above^ which is super weird
        });
  }
}

spotifySeed();

艺术家被添加到MongoDB,类型设置为[]。 之后,我得到了具有良好genreID数组的控制台输出(应该在那里^而不是类型)。

已解决 - 编辑

感谢所有帮助过的人。 问题出在findOrCreate中,因为它没有返回一个promise。 我使用这个包用于mongoose而不是Promises( https://www.npmjs.com/package/mongoose-findorcreate )。

现在的代码是

if (Array.isArray(array)) {
  // eslint-disable-next-line no-restricted-syntax
    for (const element of array) {
      await Genre.findOrCreate({ name: element })
        .then((result) => {
          genreIDs.push(result.doc._id);
        });
    }
  }

在SpotifySeed中

const genreIDs = await fillGenres(entry.Genres);
      await fillRest(entry, genreIDs);

我之前没有使用过Spotify API,所以我不能说太多,但我乍一看有几个问题。 首先,你要检查if (array !== 'undefined') { ,这是检查array变量是否是一个字面上'undefined'的字符串(不是undefined的值)。 我很确定这不是你想要的。 如果你想确保array实际上是一个数组,你最好在这里使用Array.isArray(array)

其次,你正在使用异步函数和Promise混合在一起,这些(imo),你通常不应该这样做。 您应该使用其中一个,因此它一致且易于遵循。 如果你使用await而不是.then ,你将能够以更“同步”的方式编写它,它应该更容易理解。

import * as data from '../spotify_data/artist_id.json';

async function fillGenres(array) {
  const genreIDs = []; // array of genre object IDs I'm trying to put inside every appropriate artist

  if (Array.isArray(array)) {
    for (const element of array) {
      const result = await Genre.findOrCreate({ name: element });
      genreIDs.push(result._id);
    }
  }

  return genreIDs;
}

async function fillRest(entry, genreIDs) {
  const artist = {
    name: entry.ArtistName,
    genres: genreIDs,
    spotifyID: entry.ArtistID,
    popularity: entry.Popularity,
    spotifyFollowers: entry.Followers,
  };

  try {
    const result = await Artist.create([artist]);
    console.log(result);
  } catch (error) {
    console.log(error);
  }
}

async function spotifySeed() {
  const entries = Object.values(data);

  for (const entry of entries) {
     const genreIDs = await fillGenres(entry.Genres);
     await fillRest(entry, genreIDs);
  }
}

await spotifySeed();

我对Spotify API一无所知,所以这只是猜测。 fillGenres ,您有:

await Genre.findOrCreate({ name: element }, (err, result) => {
  genreIDs.push(result._id);
});

你正在传递一个回调函数。 有时库会允许您使用promises callbacks。 如果您传递回调,它将不会返回承诺。 所以我猜测循环开始对Genre.findOrCreate所有调用,因为你正在使用回调,它不会返回一个承诺。 然后立即返回。 然后fillRest并在所有Genre.findOrCreate调用之前完成。

你想要的东西:

const result = await Genre.findOrCreate({ name: element });
genreIDs.push(result._id)

虽然更好的是:

function fillGenres(genreNames) {
  if(!genreNames || !genreNames.length) return Promise.resolve([])

  return Promise.all(genreNames.map(name => {
    return Genre.findOrCreate({ name })
      .then(result => result._id)
  })
}

这将同时运行所有类型调用并在完成后将它们全部返回,而不是等待一个接一个地添加(如在for循环中)。

如果Genre.findOrCreate没有返回Promise,您可以创建一个版本:

function genreFindOrCreate(data) {
  return new Promise((resolve, reject) => {
    Genre.findOrCreate(data, (err, result) => {
      if(err) reject(err)
      else resolve(result)
    })
  })
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM