[英]Resolve any number promises nested inside of an object
我有一个在各个位置都有嵌套File
实例的对象。 我想递归地遍历对象,检查对象是否为instanceof File
的instanceof File
,使用promise从实例创建数据URL,并仅在所有promise都已解决时才解析promise。
我有一个现有函数,该函数返回Promise并在文件中的数据URL准备就绪时进行解析。
export const parsePhoto = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
try {
reader.readAsDataURL(file);
reader.onloadend = () => {
return resolve(reader.result);
}
} catch(e) {
console.warn('Could not upload photo', e.target);
}
})
}
我有一个函数可以在对象中递归查找File
。
export const convertPhotosToBase64 = (values) => {
if (!values) return values;
const converted = Object.keys(values).reduce((acc, key) => {
if (values[key] instanceof File) {
// Do something here
acc[key] = parsePhoto(values[key]);
}
if (isArray(values[key])) {
acc[key] = values[key].map(value => {
if (typeof value === 'object' && !isArray(value)) {
return convertPhotosToBase64(value);
}
return value;
})
}
// Recurse if object
if (typeof values[key] === 'object' && !isArray(values[key])) {
acc[key] = convertPhotosToBase64(values[key]);
}
return acc;
}, values);
return converted;
}
我想保留传递的对象的现有结构( values
),仅用base64字符串替换File实例。
我也知道Promise.all
但不确定如何在这种情况下使用它。
当所有文件都已转换为base64字符串时,如何返回convertPhotosToBase64
作为可解决的承诺?
让我们首先简化一下功能,以减少所有这些条件的重复:
export function convertPhotosToBase64(value) {
if (typeof value !== 'object') return value;
if (value instanceof File) return parsePhoto(value);
if (isArray(value)) return value.map(convertPhotosToBase64);
return Object.keys(value).reduce((acc, key) => {
acc[key] = convertPhotosToBase64(value[key]);
return acc;
}, {});
}
现在, parsePhoto
是异步的并返回一个parsePhoto
。 这意味着整个convertPhotosToBase64
将需要变得异步并始终返回promise。 考虑到四种明显不同的情况,这实际上比听起来简单:
export function convertPhotosToBase64(value) {
// wrap value
if (typeof value !== 'object') return Promise.resolve(value);
// already a promise
if (value instanceof File) return parsePhoto(value);
// map creates all the promises in parallel, use `Promise.all` to await them
if (isArray(value)) return Promise.all(value.map(convertPhotosToBase64));
// chain one after the other
return Object.keys(value).reduce((accP, key) =>
accP.then(acc =>
convertPhotosToBase64(value[key]).then(res => {
acc[key] = res;
return acc;
})
)
, Promise.resolve({}));
}
如果可以并行进行所有操作(不仅限于数组),还可以将最后一种情况简化为:
return Object.keys(value).reduce((accP, key) =>
Promise.all([accP, convertPhotosToBase64(value[key])]).then([acc, res] => {
acc[key] = res;
return acc;
})
, Promise.resolve({}));
也许更好
const keys = Object.keys(value);
return Promise.all(keys.map(key => convertPhotosToBase64(value[key])).then(results => {
const acc = {};
for (const [key, i] of keys.entries())
acc[key] = results[i];
return acc;
});
Promise.all
您的要求。 在这种情况下使用它的最简单方法是在函数底部执行return Promise.all(converted)
,它将返回一个特殊的promise,该return Promise.all(converted)
必须在参数中的所有promise都解决后才能解决。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.