我是React Native的新手,在一个无法解决的问题上挣扎了很长时间。
我解析了一个包含艺术家和曲目信息的在线JSON文件。该网站唯一没有提供的是一个图像URL。所以我尝试使用lastfmapi来解析这个。
我设法从lastfm API获得了URL,但除了呈现基本JSON之外,我不确定如何有效地呈现它。
我试着用我需要的东西重新创建这个对象,但我总是在解析它时遇到困难。我总是遇到未定义或函数错误。
下面是最后一次尝试(不确定这是否是完整的一次)。我试了很长时间,所以这可能会一团糟。不要因为这个向我开枪哈哈
async initializeNowPlaying () {
await fetch (nowPlayingUrl + showNumberOfTracks)
.then (response => response.json ())
.then (responseJson => {
id = JSON.stringify (responseJson.nowplaying[0].id).replace (/"/g, '');
title = JSON.stringify (responseJson.nowplaying[0].title).replace (
/"/g,
''
);
artist = JSON.stringify (responseJson.nowplaying[0].artist).replace (
/"/g,
''
);
dateTime = JSON.stringify (
responseJson.nowplaying[0].datetime
).replace (/"/g, '');
showName = JSON.stringify (
responseJson.nowplaying[0].showName
).replace (/"/g, '');
fetch (
'https://ws.audioscrobbler.com/2.0/?method=track.getInfo&format=json&api_key=my_key&artist=' +
this.artist +
'&track=' +
this.title
)
.then (response => response.json ())
.then (responseJson => {
if (responseJson !== 'undefined' || responseJson !== '') {
albumUrl = responseJson.track.album.image[3]['#text'];
} else {
albumUrl = 'https://replacedomain.com/logo.png';
}
})
.catch (error => {
console.log (
'Geen afbeelding aanwezig. Standaard afbeelding geretourneerd: ' +
error
);
albumUrl = 'https://replacedomain.com/logo.png';
});
});
const obj = {
id: id,
datetime: dateTime,
artist: artist,
title: title,
albumUrl: albumUrl,
showName: 'showName',
};
oldObject = this.state.NowPlaying;
newArray = [obj, ...oldObject];
this.setState ({
NowPlaying: newArray,
});
}
有人能给我指正确的方向吗?
谢谢!!
我想我能看到你在做什么,但你的代码中有很多混乱。
你似乎不理解async/await
和promises
之间的区别,这篇文章有一个很好的解释https://medium.com/@bluepnume/learn-about-requestes-fore-you-start-using-async-await-eb148164a9c8
让我们尝试重构您的代码,使其更易于阅读,更有意义。我使用async/await
,因为它可以比使用promises
更干净、更容易地读取代码。这也意味着我不必担心全局变量,也不必试图从promise内部更新它们,这可能会变得棘手,因为有些代码将同步运行,而另一些代码将异步运行。使用async/await
意味着代码将等待,直到await
代码完成后再执行下一行。
- 首先删除所有promise并使用
async/await
,将所有内容包装在try/catch
中,因为等待可以抛出 - 下载nowPlayingResponse并获取其json
- 获取最终对象所需的所有变量,在访问可能存在也可能不存在的数组时,您可能需要一些保护
- 下载albumResponse并获取其json
- 设置一个默认的albumUrl并更新它(如果可以从json中获取),也许这里有更多的保护,而不仅仅是访问对象的一部分
- 最后构造对象并更新状态
- 在catch中,您应该处理您遇到的任何错误
这是重构
async initializeNowPlaying () {
try {
let nowPlayingResponse = await fetch(nowPlayingUrl + showNumberOfTracks);
let nowPlayingJson = await nowPlayingResponse.json();
let id = JSON.stringify(nowPlayingJson.nowplaying[0].id).replace(/"/g, '');
let title = JSON.stringify(nowPlayingJson.nowplaying[0].title).replace(/"/g,'');
let artist = JSON.stringify(nowPlayingJson.nowplaying[0].artist).replace(/"/g,'');
let dateTime = JSON.stringify(nowPlayingJson.nowplaying[0].datetime).replace(/"/g, '');
let showName = JSON.stringify(nowPlayingJson.nowplaying[0].showName).replace(/"/g, '');
let albumResponse = await fetch (`https://ws.audioscrobbler.com/2.0/?method=track.getInfo&format=json&api_key=my_key&artist=${artist}&track=${title}`);
let albumJson = await albumResponse.json();
let albumUrl = 'https://replacedomain.com/logo.png';
if (albumJson !== 'undefined' || albumJson !== '') {
albumUrl = responseJson.track.album.image[3]['#text'];
}
const obj = {
id: id,
datetime: dateTime,
artist: artist,
title: title,
albumUrl: albumUrl,
showName: 'showName',
};
let oldObject = this.state.NowPlaying;
let newArray = [obj, ...oldObject];
this.setState ({ NowPlaying: newArray });
} catch (err) {
console.warn(err);
}
}
显然,我无法对此进行测试(因为我没有所有的api、密钥等),所以这实际上只是一个指南,但它应该让你对如何让代码工作有一个很好的想法。我想你也会同意,阅读和理解正在发生的事情要容易得多。
正在下载所有项目
从你的评论中可以看出,你实际上想下载相册图像的所有URL,并更新播放列表中的项目。您可以使用Promise.all
来允许执行多个请求尽管这可能需要相当长的时间来执行,因为这将取决于您试图下载的相册数量您可以在此处阅读有关使用Promise.all
的更多信息https://www.taniarascia.com/promise-all-with-async-await/
- 将创建相册对象的代码重新转换为自己的函数。如果调用成功,它将返回/解析到具有正确相册url的相册对象,否则为默认url
- 使用
Promise.all
在nowPlayingJson.nowplaying
数组上循环,这将发出每个请求,但直到所有循环都完成,每个承诺都得到解决,它才会完成 - 将旧的nowPLaying与新的nowPLay组合更新setState
这是新代码:
async initializeNowPlaying () {
try {
let nowPlayingResponse = await fetch (nowPlayingUrl + showNumberOfTracks);
let nowPlayingJson = await nowPlayingResponse.json();
let newArray = []
Promise.all(
nowPlayingJson.nowplaying.map(async album => {
const albumObj = await getAlbumObject(album)
newArray.push(albumObj);
});
);
let oldObject = this.state.NowPlaying;
newArray = [...newArray, ...oldObject];
this.setState ({ NowPlaying: newArray });
} catch (err) {
console.warn(err);
}
}
async getAlbumObject (album) {
return new Promise(async (resolve, reject) => {
let id = JSON.stringify(album.id).replace(/"/g, '');
let title = JSON.stringify(album.title).replace(/"/g,'');
let artist = JSON.stringify(album.artist).replace(/"/g,'');
let dateTime = JSON.stringify(album.datetime).replace(/"/g, '');
let showName = JSON.stringify(album.showName).replace(/"/g, '');
let albumUrl = 'https://replacedomain.com/logo.png';
let obj = { id, title, artist, dateTime, showName, albumUrl };
try {
let albumResponse = await fetch (`https://ws.audioscrobbler.com/2.0/?method=track.getInfo&format=json&api_key=my_key&artist=${artist}&track=${title}`);
let albumJson = await albumResponse.json();
if (albumJson !== 'undefined' || albumJson !== '') {
let url = albumJson.track.album.image[3]['#text'];
if (url) obj.albumUrl = url;
}
resolve(obj);
} catch (err) {
resolve(obj);
}
})
}
同样,我不能测试这个,但它应该给你一个如何做到这一点的想法。