JS,多个JSON请求和回调函数
JS, multiple JSON requests and callback functions
我需要一些帮助。我是 Javascript 的新手,我目前正在尝试使用 两个不同的 api:SongKick 和 Deezer。这个想法很简单,在页面上你可以输入你的城市,1) 我向 Songkick 发出第一个请求 Api 以获取这个城市的 ID,2) 然后用 ID,我做了另一个请求来获取音乐会列表,我只取了艺术家的名字(最多 20 个),3)然后我用名字列表使用 deezer Api 获取艺术家的照片和 mp3 预览。
我试过很多方法当然不能到处访问数据,而且我不知道怎么使用回调因为东西太多了,如果你能看一下就太棒了.
谢谢!
artistsArray = [];
artistsArray2 = [];
arr = [artistsArray,[],[]];
var dispName;
var areaId;
function search(){
area = document.getElementById('band').value;
function songKickArea(callback){
$.getJSON('http://api.songkick.com/api/3.0/search/locations.json?query=' + area + '&apikey=tIhpFoFn0dWpQ72A',function(data){
var areaId = data['resultsPage']['results']['location'][0].metroArea.id;
callback(areaId);
});
console.log("1 is done");
}
function findAreaId(callback){
songKickArea(function(callback){
console.log(callback);
});
$.getJSON("http://api.songkick.com/api/3.0/metro_areas/" + areaId + "/calendar.json?apikey=tIhpFoFn0dWpQ72A",function(data){
for (var i=0; i<20 ; i++)
{
artistsArray.push(data['resultsPage']['results']['event'][i].performance[0].displayName);
}
callback(artistsArray);
});
console.log("2 is done");
}
function addInfos(callback){
for (var i=0; i<20 ; i++)
{
DZ.api('/search?q=artist:' + '"'+ artistsArray[i]+'"' +'?limit=1', function(json){
if(json.data[0]){
artistsArray2.push({preview:json.data[0].preview, picture: json.data[0].artist.picture})
}
});
}
console.log("3 is done");
callback();
}
function runSearchInOrder(callback) {
songKickArea(function() {
findAreaId(function() {
addInfos(function() {
console.log(areaId);
});
});
});
}
runSearchInOrder(function(){console.log('finished')});
}
编辑 2015 年 9 月 17 日
谢谢 Vittore,我看了一下 JS 中的 promises,它对我来说非常有趣和完美。所以现在我来了:
function songKickArea(areaId){
area = document.getElementById('band').value;
return $.getJSON('http://api.songkick.com/api/3.0/search/locations.json?query=' + area + '&apikey=XXXXXXX',function(data){
});
}
function findAreaId(data){
var areaId = data['resultsPage']['results']['location'][0].metroArea.id;
return $.getJSON("http://api.songkick.com/api/3.0/metro_areas/" + areaId + "/calendar.json?apikey=XXXXXXX",function(data){
});
}
function addInfos(data){
for (var i=0; i<20 ; i++)
{
artistsArray.push(data['resultsPage']['results']['event'][i].performance[0].displayName);
DZ.api('/search?q=artist:' + '"'+ artistsArray[i]+'"' +'?limit=1', function(json){
if(json.data[0]){
artistsArray2.push({preview:json.data[0].preview, picture: json.data[0].artist.picture})
}
});
}
}
我使用这个 onClick:
songKickArea().then(findAreaId).then(addInfos).then(createList);
所以一切正常,在 addInfos 中,我的数组 artistsArray2 从 deezer 获取我需要的所有信息(预览和图片)。但是现在下一步是创建一个列表来显示这些艺术家(或曲目)所以下一个函数是这样的。
function createList(json){
var html = '<ul>';
for (var i=0; i<17; i++)
{
html+= '<li>';
html += '<div class="picture">' + '<div class="player"><img src="svg/play43.svg" ></div>'+ '<a href=' + artistsArray2[i].preview + '>' + '<img src=' + artistsArray2[i].picture + '>' + '</a>' +'</div>';
html+= '<div class="arrow"><img src="css/svg/arrow487.svg"></div>';
html+= '</li>';
}
html+= '</ul>';
$('#results').append(html);
}
但是我不知道如何将完整数组的值从最后一个函数传递给这个函数,你能帮我吗?非常感谢 !
更新:对多次调用服务和结果数组的说明很少。
您的原始代码具有 addInfos
方法,该方法通过数组迭代(for 循环)并在该循环中调用 Web 服务。您想要做的是一起获得每个调用的结果。虽然有很多方法可以做到这一点,但我向您展示的是使用 array.map
到 "map" 数组的每个元素,其中包含从步骤 X 到由 [=87 编辑的承诺 return 的数据=] 打电话。让我举个例子:
假设你有一个数组:
var artistIds = [6664009,6664010,6664011]
现在您可以将其映射到承诺:
var artistCalls = artistIds.map(function(id) {
return $.getJson('~ get artists data service url ~' + id)
}
这将为您提供数组 artistCalls
,其中的每个元素最终都会用您需要的数据解决承诺。虽然你可以用它做所有疯狂的事情,但从所有调用中获取数据的最简单方法是使用 $.when
辅助方法:
$.when(artistCalls).then(function(artists) {
// here artists will array where each element is data returned by each AJAX call
})
现在,如果您想要呈现 html 以显示页面上的所有艺术家,您可能需要这样的代码:
function renderArtistHtml(artist) {
return '<li>'
+= '<div class="picture"><div class="player"><img src="svg/play43.svg" ></div><a href="' + artistsArray2[i].preview + '"><img src="' + artistsArray2[i].picture + '"></a></div>'
+= '<div class="arrow"><img src="css/svg/arrow487.svg"></div>'
+= '</div></li>';
}
以及呈现整个列表的函数:
function renderAllArtistsHtml(artists) {
return '<ul>' + artists.map(renderArtistHtml) + '</ul>'
}
现在您已经拥有它,您可以一起创建整个函数链:
$(... my button selector ...).on('click',function(e) {
var area = ... get area
songKickArea(area)
.then(findAreaId) // this thing returns promise that returns array
.then(addInfos) // this thing returns $.when(arr.map(...))
.then(renderAllArtistsHtml) // this thing converts array of data from all calls from previous step to html layout
.then(function(html) { // this part just adds it to DOM
$('#results').append(html);
});
})
刚刚回答了类似的问题。
基本上 jquery return 承诺中的每个 ajax 方法(如果你的 api 没有 return 承诺(比如 DZ.api
) 你可以把它包裹在 $.deferred
)
一旦您 return 从您的函数中承诺,您就可以将它们链接起来:
function myajax1() {
return $.getJson(...)
}
function myajax2(data) {
return $.getJson(...)
}
myajax1().then(myajax2)
这将使用 myajax1
编辑的数据 return 调用 myajax2
ajax 调用
您可以将其链接任意多次。
如果您需要等待几个,您可以使用 $.when:
$.when([myajax11(), myajax12()]).then(myajax2)
如此接近您的实际代码,您有 3 api 个调用:
- songkick 地点
- songkick metro_areas
- DZ.api
最后一个需要在承诺中结束,请参见此处的示例:https://learn.jquery.com/code-organization/deferreds/examples/
声明 3 个函数:
function getLocations(area) {
return $.getJson(....) // location query
}
function getMetroArea(data) {
var areaId = data['resultsPage']['results']['location'][0].metroArea.id
return $.getJson(...) // metro query
}
function getArtists(data) {
var artist = data['resultsPage']['results']['event'][i].performance[0].displayName
return DZAPIWraper(...)
}
并将它们链接起来:
getLocations(...).then(getMetroArea).then(getArtists)
如果您确实需要在最后一步中多次调用多个艺术家,您的代码将类似于:
function getArtists(data) {
var artists = getArtistsArrayFromMetro(data)
var artistsCallbacks = artists.map(function(a) {
return DZAPIWrapper(...)
})
return $.when(artistCallbacks)
}
完整链是:
getLocations(...).then(getMetroArea).then(getArtists).then(function(artists) {
// here artists going to be all artists data from all api calls to DZ.api
})
我需要一些帮助。我是 Javascript 的新手,我目前正在尝试使用 两个不同的 api:SongKick 和 Deezer。这个想法很简单,在页面上你可以输入你的城市,1) 我向 Songkick 发出第一个请求 Api 以获取这个城市的 ID,2) 然后用 ID,我做了另一个请求来获取音乐会列表,我只取了艺术家的名字(最多 20 个),3)然后我用名字列表使用 deezer Api 获取艺术家的照片和 mp3 预览。
我试过很多方法当然不能到处访问数据,而且我不知道怎么使用回调因为东西太多了,如果你能看一下就太棒了.
谢谢!
artistsArray = [];
artistsArray2 = [];
arr = [artistsArray,[],[]];
var dispName;
var areaId;
function search(){
area = document.getElementById('band').value;
function songKickArea(callback){
$.getJSON('http://api.songkick.com/api/3.0/search/locations.json?query=' + area + '&apikey=tIhpFoFn0dWpQ72A',function(data){
var areaId = data['resultsPage']['results']['location'][0].metroArea.id;
callback(areaId);
});
console.log("1 is done");
}
function findAreaId(callback){
songKickArea(function(callback){
console.log(callback);
});
$.getJSON("http://api.songkick.com/api/3.0/metro_areas/" + areaId + "/calendar.json?apikey=tIhpFoFn0dWpQ72A",function(data){
for (var i=0; i<20 ; i++)
{
artistsArray.push(data['resultsPage']['results']['event'][i].performance[0].displayName);
}
callback(artistsArray);
});
console.log("2 is done");
}
function addInfos(callback){
for (var i=0; i<20 ; i++)
{
DZ.api('/search?q=artist:' + '"'+ artistsArray[i]+'"' +'?limit=1', function(json){
if(json.data[0]){
artistsArray2.push({preview:json.data[0].preview, picture: json.data[0].artist.picture})
}
});
}
console.log("3 is done");
callback();
}
function runSearchInOrder(callback) {
songKickArea(function() {
findAreaId(function() {
addInfos(function() {
console.log(areaId);
});
});
});
}
runSearchInOrder(function(){console.log('finished')});
}
编辑 2015 年 9 月 17 日
谢谢 Vittore,我看了一下 JS 中的 promises,它对我来说非常有趣和完美。所以现在我来了:
function songKickArea(areaId){
area = document.getElementById('band').value;
return $.getJSON('http://api.songkick.com/api/3.0/search/locations.json?query=' + area + '&apikey=XXXXXXX',function(data){
});
}
function findAreaId(data){
var areaId = data['resultsPage']['results']['location'][0].metroArea.id;
return $.getJSON("http://api.songkick.com/api/3.0/metro_areas/" + areaId + "/calendar.json?apikey=XXXXXXX",function(data){
});
}
function addInfos(data){
for (var i=0; i<20 ; i++)
{
artistsArray.push(data['resultsPage']['results']['event'][i].performance[0].displayName);
DZ.api('/search?q=artist:' + '"'+ artistsArray[i]+'"' +'?limit=1', function(json){
if(json.data[0]){
artistsArray2.push({preview:json.data[0].preview, picture: json.data[0].artist.picture})
}
});
}
}
我使用这个 onClick:
songKickArea().then(findAreaId).then(addInfos).then(createList);
所以一切正常,在 addInfos 中,我的数组 artistsArray2 从 deezer 获取我需要的所有信息(预览和图片)。但是现在下一步是创建一个列表来显示这些艺术家(或曲目)所以下一个函数是这样的。
function createList(json){
var html = '<ul>';
for (var i=0; i<17; i++)
{
html+= '<li>';
html += '<div class="picture">' + '<div class="player"><img src="svg/play43.svg" ></div>'+ '<a href=' + artistsArray2[i].preview + '>' + '<img src=' + artistsArray2[i].picture + '>' + '</a>' +'</div>';
html+= '<div class="arrow"><img src="css/svg/arrow487.svg"></div>';
html+= '</li>';
}
html+= '</ul>';
$('#results').append(html);
}
但是我不知道如何将完整数组的值从最后一个函数传递给这个函数,你能帮我吗?非常感谢 !
更新:对多次调用服务和结果数组的说明很少。
您的原始代码具有 addInfos
方法,该方法通过数组迭代(for 循环)并在该循环中调用 Web 服务。您想要做的是一起获得每个调用的结果。虽然有很多方法可以做到这一点,但我向您展示的是使用 array.map
到 "map" 数组的每个元素,其中包含从步骤 X 到由 [=87 编辑的承诺 return 的数据=] 打电话。让我举个例子:
假设你有一个数组:
var artistIds = [6664009,6664010,6664011]
现在您可以将其映射到承诺:
var artistCalls = artistIds.map(function(id) {
return $.getJson('~ get artists data service url ~' + id)
}
这将为您提供数组 artistCalls
,其中的每个元素最终都会用您需要的数据解决承诺。虽然你可以用它做所有疯狂的事情,但从所有调用中获取数据的最简单方法是使用 $.when
辅助方法:
$.when(artistCalls).then(function(artists) {
// here artists will array where each element is data returned by each AJAX call
})
现在,如果您想要呈现 html 以显示页面上的所有艺术家,您可能需要这样的代码:
function renderArtistHtml(artist) {
return '<li>'
+= '<div class="picture"><div class="player"><img src="svg/play43.svg" ></div><a href="' + artistsArray2[i].preview + '"><img src="' + artistsArray2[i].picture + '"></a></div>'
+= '<div class="arrow"><img src="css/svg/arrow487.svg"></div>'
+= '</div></li>';
}
以及呈现整个列表的函数:
function renderAllArtistsHtml(artists) {
return '<ul>' + artists.map(renderArtistHtml) + '</ul>'
}
现在您已经拥有它,您可以一起创建整个函数链:
$(... my button selector ...).on('click',function(e) {
var area = ... get area
songKickArea(area)
.then(findAreaId) // this thing returns promise that returns array
.then(addInfos) // this thing returns $.when(arr.map(...))
.then(renderAllArtistsHtml) // this thing converts array of data from all calls from previous step to html layout
.then(function(html) { // this part just adds it to DOM
$('#results').append(html);
});
})
刚刚回答了类似的问题
基本上 jquery return 承诺中的每个 ajax 方法(如果你的 api 没有 return 承诺(比如 DZ.api
) 你可以把它包裹在 $.deferred
)
一旦您 return 从您的函数中承诺,您就可以将它们链接起来:
function myajax1() {
return $.getJson(...)
}
function myajax2(data) {
return $.getJson(...)
}
myajax1().then(myajax2)
这将使用 myajax1
编辑的数据 return 调用 myajax2
ajax 调用
您可以将其链接任意多次。
如果您需要等待几个,您可以使用 $.when:
$.when([myajax11(), myajax12()]).then(myajax2)
如此接近您的实际代码,您有 3 api 个调用:
- songkick 地点
- songkick metro_areas
- DZ.api
最后一个需要在承诺中结束,请参见此处的示例:https://learn.jquery.com/code-organization/deferreds/examples/
声明 3 个函数:
function getLocations(area) {
return $.getJson(....) // location query
}
function getMetroArea(data) {
var areaId = data['resultsPage']['results']['location'][0].metroArea.id
return $.getJson(...) // metro query
}
function getArtists(data) {
var artist = data['resultsPage']['results']['event'][i].performance[0].displayName
return DZAPIWraper(...)
}
并将它们链接起来:
getLocations(...).then(getMetroArea).then(getArtists)
如果您确实需要在最后一步中多次调用多个艺术家,您的代码将类似于:
function getArtists(data) {
var artists = getArtistsArrayFromMetro(data)
var artistsCallbacks = artists.map(function(a) {
return DZAPIWrapper(...)
})
return $.when(artistCallbacks)
}
完整链是:
getLocations(...).then(getMetroArea).then(getArtists).then(function(artists) {
// here artists going to be all artists data from all api calls to DZ.api
})