[英]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.