无法在递归承诺函数中解决
Unable to resolve within recursive promise function
我想我从根本上误解了 Promises 在 Node 中的工作方式。
我正在编写一个非常小的 Express 应用程序,我想 return JSON 我所有包含特定关键字的 Spotify 播放列表。我正在使用来自 npm 的 spotify-web-api-node
。
Spotify 的 API 限制每个请求 50 个播放列表。我有(我认为的)解决方案:只需增加偏移值,直到您不再需要为止。
我的函数如下所示(playlists
在路由函数上方声明):
app.get('/playlists', function(req, res) {
addPlaylistsToList()
.then((data) => res.json(data))
});
function addPlaylistsToList(offset) {
if (!offset) { offset = 0; }
var limit = 50;
return new Promise((resolve, reject) => {
spotifyApi.getUserPlaylists(config.USER, { limit: limit, offset: offset })
.then(function(data) {
playlists.push(data.body.items.filter((playlist) => playlist.name.includes(config.TITLE_CONDITION)));
if (data.body.items.length == limit) {
addPlaylistsToList(offset + limit);
} else {
let result = [...new Set(playlists)];
resolve(result);
}
})
});
}
我不能在这里打电话给 resolve
吗?我的意思是,我知道我不能,因为我陷入了无限循环。是否有 "best practice" re: 递归承诺?我在滥用 then
吗?
使用递归承诺通常没问题,但您在实施过程中遗漏了一些东西。每次调用 addPlaylistsToList()
都会创建一个新的承诺,但只有一次调用会创建一个实际解决的新承诺:最后一个。所有其他创建的承诺将无限期待定。
您可以用更典型的递归风格重写函数,如下所示:
function addPlaylistsToList(offset = 0) { //default parameter value to 0
var limit = 50;
return spotifyApi.getUserPlaylists(config.USER, { limit: limit, offset: offset })
.then(function(data) {
playlists.push(data.body.items.filter((playlist) => playlist.name.includes(config.TITLE_CONDITION)));
if (data.body.items.length == limit) {
return addPlaylistsToList(offset + limit); //return a promise
} else {
return [...new Set(playlists)]; //return the final value
}
});
}
(未经测试)
这是有效的,因为向 .then()
回调返回承诺会导致 .then()
到 "follow" 返回的承诺 - 它只会在 that[=26] 时解析=] 承诺解决,等等。您可以像这样递归地链接 promises,最终最底部的一个将用您的结果数组解析,导致所有其他的也用该数组解析。
另外,使用 async/await:
可以写得更简洁
async function addPlaylistsToList(offset = 0) { //default parameter value to 0
var limit = 50;
var data = await spotifyApi.getUserPlaylists(config.USER, { limit: limit, offset: offset });
playlists.push(data.body.items.filter((playlist) => playlist.name.includes(config.TITLE_CONDITION)));
if (data.body.items.length == limit) {
return await addPlaylistsToList(offset + limit);
} else {
return [...new Set(playlists)];
}
}
我想我从根本上误解了 Promises 在 Node 中的工作方式。
我正在编写一个非常小的 Express 应用程序,我想 return JSON 我所有包含特定关键字的 Spotify 播放列表。我正在使用来自 npm 的 spotify-web-api-node
。
Spotify 的 API 限制每个请求 50 个播放列表。我有(我认为的)解决方案:只需增加偏移值,直到您不再需要为止。
我的函数如下所示(playlists
在路由函数上方声明):
app.get('/playlists', function(req, res) {
addPlaylistsToList()
.then((data) => res.json(data))
});
function addPlaylistsToList(offset) {
if (!offset) { offset = 0; }
var limit = 50;
return new Promise((resolve, reject) => {
spotifyApi.getUserPlaylists(config.USER, { limit: limit, offset: offset })
.then(function(data) {
playlists.push(data.body.items.filter((playlist) => playlist.name.includes(config.TITLE_CONDITION)));
if (data.body.items.length == limit) {
addPlaylistsToList(offset + limit);
} else {
let result = [...new Set(playlists)];
resolve(result);
}
})
});
}
我不能在这里打电话给 resolve
吗?我的意思是,我知道我不能,因为我陷入了无限循环。是否有 "best practice" re: 递归承诺?我在滥用 then
吗?
使用递归承诺通常没问题,但您在实施过程中遗漏了一些东西。每次调用 addPlaylistsToList()
都会创建一个新的承诺,但只有一次调用会创建一个实际解决的新承诺:最后一个。所有其他创建的承诺将无限期待定。
您可以用更典型的递归风格重写函数,如下所示:
function addPlaylistsToList(offset = 0) { //default parameter value to 0
var limit = 50;
return spotifyApi.getUserPlaylists(config.USER, { limit: limit, offset: offset })
.then(function(data) {
playlists.push(data.body.items.filter((playlist) => playlist.name.includes(config.TITLE_CONDITION)));
if (data.body.items.length == limit) {
return addPlaylistsToList(offset + limit); //return a promise
} else {
return [...new Set(playlists)]; //return the final value
}
});
}
(未经测试)
这是有效的,因为向 .then()
回调返回承诺会导致 .then()
到 "follow" 返回的承诺 - 它只会在 that[=26] 时解析=] 承诺解决,等等。您可以像这样递归地链接 promises,最终最底部的一个将用您的结果数组解析,导致所有其他的也用该数组解析。
另外,使用 async/await:
可以写得更简洁async function addPlaylistsToList(offset = 0) { //default parameter value to 0
var limit = 50;
var data = await spotifyApi.getUserPlaylists(config.USER, { limit: limit, offset: offset });
playlists.push(data.body.items.filter((playlist) => playlist.name.includes(config.TITLE_CONDITION)));
if (data.body.items.length == limit) {
return await addPlaylistsToList(offset + limit);
} else {
return [...new Set(playlists)];
}
}