簡體   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