问题描述
我正试图从Cloudinary中获取所有照片,但是每次调用限制为500个元素。
呼叫中存在一个名为next_cursor
的属性,您可以将其用作分页。
我以递归方式进行操作,但是当我尝试在Express中发送响应超出范围时,关于如何使用递归函数的结果进行响应的任何想法?
谢谢!
const express = require("express");
const router = express.Router();
const cloudinary = require("cloudinary").v2;
const { cloudinarySettings } = require("../config/cloudinary_config");
router.get("/statistics",async (req,res) => {
function list_resources(results,next_cursor = null) {
cloudinary.api.resources(
{
resource_type: "image",mex_results: 500,next_cursor: next_cursor,},function (err,res) {
console.log(err);
res.resources.forEach(function (resource) {
results.push(resource);
});
if (res.next_cursor) {
list_resources(results,res.next_cursor);
} else {
return res.status(200).json(results)
}
}
);
}
const results = [];
list_resources(results);
});
解决方法
您将需要修改list_resources
函数以按如下方式返回promise,然后使用async-await
等待结果,然后再提交res
。
router.get("/statistics",async (req,res) => {
async function list_resources(results,next_cursor = null) {
await new Promise((resolve) => {
cloudinary.api.resources(
{
resource_type: "image",mex_results: 500,next_cursor: next_cursor,},function (err,res) {
if (err) {
console.log(err);
resolve();
} else {
res.resources.forEach(function (resource) {
results.push(resource);
});
if (res.next_cursor) {
list_resources(results,res.next_cursor).then(() => resolve());
} else {
resolve();
}
}
}
);
});
}
const results = [];
await list_resources(results);
return res.status(200).json(results);
});
,
我可能会以不同的方式分解问题,并制作一个更简单的递归函数来返回结果,而不是修改传入的数组。为了保持整洁,我还将函数移出router.get
回调。 / p>
所以它可能看起来像这样:
const listResources = async ({resource_type,max_results = 500,next_cursor = null} = {}) => {
return new Promise((resolve,reject) => {
cloudinary .api .resources (
{resource_type,max_results,next_cursor},async (err,{resources,next_cursor}) => {
try {
if (err) {reject (err)}
else resolve ([
...resources,...(next_cursor ? await listResources ({resource_type,next_cursor}) : [])
])
} catch (err) {reject (err)}
}
)
})
}
router.get('/statistics',res) => {
try {
const results = await listResources ({resource_type: 'image'})
res .status (200) .json (results)
} catch (err) {
console .warn (err)
res .status (404) // or 500,or whatever,based on error
}
})
最有趣的部分是:
resolve ([
...resources,next_cursor}) : [])
])
如果返回一个next_cursor
值,则在解析之前,将使用它的递归调用结果附加到当前结果中。如果没有得到,则附加一个空数组。
很高兴能够编写这个可以说更简单的cloudinary回调函数:
async (err,next_cursor}) => err
? reject (err)
: resolve ([
...resources,next_cursor}) : [])
])
避免使用try-catch
和if-else
块。但是我找不到一种简单的方法来将错误传递回最初调用listResources
的函数。
您可以在浏览器中使用此代码段中cloudinary
和router
的虚拟实现对此进行测试:
const listResources = async ({resource_type,next_cursor = null}) => {
return new Promise((resolve,reject) => {
cloudinary.api.resources(
{resource_type,res) => {
try {
const results = await listResources ({resource_type: 'image',max_results: 3})
res .status (200) .json (results)
} catch (err) {
console .warn (err)
res .status (500) // or whatever,based on error
}
})
.as-console-wrapper {max-height: 100% !important; top: 0}
<script>
// Dummy implementations for testing:
const cloudinary = (() => {
const vals = [{t: 'image',id: 1,v: 'a'},{t: 'image',id: 2,v: 'b'},id: 3,v: 'c'},{t: 'pdf',id: 4,v: 'd'},id: 5,v: 'e'},id: 6,v: 'f'},{t: 'video',id: 7,v: 'g'},id: 8,v: 'h'},id: 9,v: 'i'},id: 10,v: 'j'},id: 11,v: 'k'},id: 12,v: 'l'}];
const last = (xs) => xs.length ? xs[xs.length - 1] : undefined;
return {api: {
resources: ({resource_type,next_cursor = 0},fn) => {
const res = vals .filter (({t,id}) => t == resource_type && id > next_cursor).slice(0,max_results)
// fn (next_cursor == 3 ? 'houston,we have a problem' : null,{ // *** use to test an error condition ***
fn (null,{
resources: res,...(res.length > 0 && last(res).id < last(vals).id ? {next_cursor: last(res).id} : {})
})
}
}}
})()
const router = {
get: (path,fn) =>
fn (
{},{status: (n) => {
console.log(`returning ${n} for request to ${path}`)
return {
json: val => console.log(`Body: \n${JSON.stringify(val,null,4)}`)
}
}}
)
}
</script>
如果您取消注释虚拟虚拟代码中的替代行并注释了上一行,则可以看到cloudinary .api .resources
引发错误时的行为。