首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Promise之前执行的.then中的代码

在Promise之前执行的.then中的代码
EN

Stack Overflow用户
提问于 2019-05-22 08:30:11
回答 2查看 72关注 0票数 3

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

我要做的就是在MongoDB中找到或创建这些流派。然后将这些对象I添加到一个数组中,并在创建Artist对象时传递该数组。

但是,我的艺术家在其流派的查找或创建过程完成之前就已经在DB中创建了。

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

我尝试过从Object.values.forEach到for..of、for..in、不同的异步、promises、调制代码……

基本上在我能找到的任何地方都添加了等待(大多数可能是在错误的地方)

代码语言:javascript
复制
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中,因为它没有返回承诺。我对mongoose使用了这个包,它具有Promises (https://www.npmjs.com/package/mongoose-findorcreate)。

现在的代码是

代码语言:javascript
复制
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中

代码语言:javascript
复制
const genreIDs = await fillGenres(entry.Genres);
      await fillRest(entry, genreIDs);
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-22 09:06:37

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

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

代码语言:javascript
复制
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();
票数 3
EN

Stack Overflow用户

发布于 2019-05-22 08:52:34

我对Spotify API一无所知,所以这只是一个猜测。在fillGenres中,您可以:

代码语言:javascript
复制
await Genre.findOrCreate({ name: element }, (err, result) => {
  genreIDs.push(result._id);
});

您正在传递一个回调函数。有时,库允许您使用promises或回调。如果你传递了一个回调,它将不会返回一个promise。所以我猜这个循环是从所有对Genre.findOrCreate的调用开始的,它不会返回promise,因为您使用的是回调函数。然后立即返回。则调用fillRest,并且可以在所有Genre.findOrCreate调用之前完成。

你想要这样的东西:

代码语言:javascript
复制
const result = await Genre.findOrCreate({ name: element });
genreIDs.push(result._id)

不过,更好的方法是:

代码语言:javascript
复制
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,您可以创建一个支持以下内容的版本:

代码语言:javascript
复制
function genreFindOrCreate(data) {
  return new Promise((resolve, reject) => {
    Genre.findOrCreate(data, (err, result) => {
      if(err) reject(err)
      else resolve(result)
    })
  })
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56247861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档