我目前正试图通过承诺从Spotify API获取数据,昨天我得到了关于同一主题的另一个问题的巨大帮助:" Loop the object returned from node promise and feed to the next .then"。
我所做的是首先从我的播放列表中获取曲目,然后再调用另一个获取艺术家的API。最后我打电话给另一个获得艺术家形象的api。 现在我的问题是:如何返回我从承诺中得到的数据?
这是我获取播放列表网址的功能:
function getPlaylists(access_token) {
var options = {
url: 'https://api.spotify.com/v1/me/playlists',
headers: { 'Authorization': 'Bearer ' + access_token },
json: true
};
return new Promise(function(resolve, reject) {
request.get(options, function(error, response, body) {
var playlists = body.items;
var playlistArray = [];
playlists.forEach(function(playlist) {
var name = playlist.name;
var url = playlist.tracks.href;
playlistArray.push(url);
});
if(!error) {
resolve(playlistArray);
} else {
reject(error);
}
});
});
}
这个得到艺术家:
function getArtists(url,access_token) {
var params = {
url: url,
headers: { 'Authorization': 'Bearer ' + access_token },
json: true
};
return new Promise(function(resolve, reject) {
request.get(params, function(error, response, body) {
var tracks = body.items;
var artistArray = [];
tracks.forEach(function(artists) {
let allArtists = artists.track.artists;
allArtists.forEach(function(artist) {
artistArray.push(artist);
});
})
if(!error) {
resolve(artistArray);
} else {
reject(error);
}
});
})
}
这一个得到了艺术家的形象:
function getArtistImages(artistId) {
var options = {
url: 'https://api.spotify.com/v1/artists/' + artistId,
json: true
};
return new Promise(function(resolve, reject) {
request.get(options, function(error, response, body) {
if(error != null) {
reject(error);
} else {
resolve(body);
}
});
})
}
编辑编辑 我称这些函数的方式是这样的:
getPlaylists(access_token)
.then(playlists => Promise.all(playlists.map(playlist =>
getArtists(playlist, access_token)))
.then(artists => {
artists.map(artist => {
artist.map(a => {
console.log(a);
let component = renderToString(
<App>
<Table artists={a} />
</App>
);
res.send(
component
)
})
})
}));
它只返回第一个结果 - 显然是因为它只能在&#34; res.send()&#34;之前循环遍历forEach循环,所以我如何确保它遍历所有艺术家,在渲染视图之前?我相信我必须做另一个Promise.all(),但我不知道在哪里 - 有没有人有想法?
我很感激:)
答案 0 :(得分:1)
它的老帖子,但我认为它对某人有帮助。
我根据支持并发的承诺编写了一个插件来执行foreach。我认为你不需要并发,这使得应用其他解决方案变得更加简单。
我使用我的插件编写了代码。它有效!
'use strict';
var request = require('request')
var promiseForeach = require('promise-foreach')
function getPlaylists(access_token) {
var options = {
url: 'https://api.spotify.com/v1/me/playlists',
headers: { 'Authorization': 'Bearer ' + access_token },
json: true
};
return new Promise(function (resolve, reject) {
request.get(options, function (error, response, body) {
var playlists = body.items;
var playlistArray = [];
playlists.forEach(function (playlist) {
var name = playlist.name;
var url = playlist.tracks.href;
playlistArray.push(url);
});
if (!error) {
resolve(playlistArray);
} else {
reject(error);
}
});
});
}
function getArtists(url, access_token) {
var params = {
url: url,
headers: { 'Authorization': 'Bearer ' + access_token },
json: true
};
return new Promise(function (resolve, reject) {
request.get(params, function (error, response, body) {
var tracks = body.items;
var artistArray = [];
tracks.forEach(function (artists) {
let allArtists = artists.track.artists;
allArtists.forEach(function (artist) {
artistArray.push(artist);
});
})
if (!error) {
promiseForeach.each(artistArray,
[function (artist) {
return getArtistImages(artist.id)
}],
function (arrayOfResultOfTask, currentList) {
return {
artistId: currentList.id,
artistName: currentList.name,
artistImages: arrayOfResultOfTask[0].images
}
},
function (err, newList) {
if (err) {
console.error(err)
return;
}
resolve(newList)
})
} else {
reject(error);
}
});
})
}
function getArtistImages(artistId) {
var options = {
url: 'https://api.spotify.com/v1/artists/' + artistId,
headers: { 'Authorization': 'Bearer ' + access_token },
json: true
};
return new Promise(function (resolve, reject) {
request.get(options, function (error, response, body) {
if (error != null) {
reject(error);
} else {
resolve(body);
}
});
})
}
var access_token = 'YOUR-TOKEN';
getPlaylists(access_token)
.then(playlists => {
promiseForeach.each(playlists,
[function (playlist) {
return getArtists(playlist, access_token)
}],
function (arrayOfResultOfTask, currentList) {
return {
playlistURL: currentList,
artist: arrayOfResultOfTask[0]
}
//return renderToString(
// <App>
// <Table artists={render} />
// </App>
//);
},
function (err, newList) {
if (err) {
console.error(err)
return;
}
res.send(newList)
})
});
插件:https://www.npmjs.com/package/promise-foreach
我希望它有所帮助!
答案 1 :(得分:0)
如果我理解你的问题,听起来好像你正在试图如何真正使用Promises
的结果。
异步应用程序:
Promises
封装了一个异步结果,该结果通过传递给then()
的回调提供。
此异步主题将在整个应用程序中级联。
应用程序可以通过多种方式管理异步结果的实际情况:事件,回调,可观察性,承诺......
示例(使用事件):
这是一个原始且未经测试的示例,说明如何将异步请求中的数据注入到视图中。当我的异步请求调用我的then()
回调时,我更新了我的模型,该模型触发了一个事件来重新渲染我的视图。
这个例子存在完全的问题(即如果我不想重新渲染我的整个视图怎么办?如果我的getArtists()返回的时间比我的视图能够更快地渲染它的加载状态怎么办?)。但为简单起见,我们不会去那里。
+function(){
var _view = $('#viewport');
var _model = {...}
var _spotifyClient = new SpotifyClient(); // this contains method similar to those you included in your question
_view.on('load', onLoad);
_view.on('model:update', onModelUpdate);
function onLoad() {
_spotifyClient
.getArtists()
.then(function(result) {
// when the getArtists() request has responded, I can update my model.
updateModel({ isLoading: false, artists: result });
})
// this will happen immediately after starting the "getArtists()" request.
udpateModel({ isLoading: true });
}
function updateModel(mod) {
for(var p in mod) {
_model[p] = mod[p];
}
_view.trigger('model:update', _model);
}
function onModelUpdate(model) {
refreshView();
}
function refreshView() {
var viewModel = buildTemplateModel(_model);
renderTemplate(_view, viewModel);
}
}();
我鼓励您研究一些视图框架,例如角度,敲门或反应。我还鼓励您研究Reactive Extensions,它提供了一个可观察的接口和许多关于异步流的实用程序。
关于副作用的注意事项:
具有承诺触发事件的结果可被归类为&#34;副作用&#34;。您应该在我们的应用程序中将副作用保持在最低限度,并且它们实际上只属于应用程序的控制器/主要部分。
如果你在你的应用程序中使用promises,那么可以使用promises的可重用库类和函数应该返回promises。
答案 2 :(得分:0)
您需要在所有结果的数组上调用res.send
,而不是分别在每个结果上调用:
getPlaylists(access_token).then(playlists =>
Promise.all(playlists.map(playlist =>
getArtists(playlist, access_token)
))
).then(artists => {
res.send(artists.map(artist =>
artist.map(a => {
console.log(a);
return renderToString(
<App>
<Table artists={a} />
</App>
);
})
))
});
此外,您的括号内容略有错误(与then
来电的缩进不匹配),但这并未导致问题。