Javascript 解析嵌套在对象内部的任意数量的承诺

Javascript 解析嵌套在对象内部的任意数量的承诺,javascript,object,promise,filereader,traversal,Javascript,Object,Promise,Filereader,Traversal,我有一个对象,在不同的位置有嵌套的文件实例。我希望递归地遍历对象,检查对象是否是文件的实例,使用承诺从实例创建数据url,并仅在所有承诺都已解决时才解决承诺 我有一个现有函数,它返回一个承诺,并在文件中的数据URL就绪时解析 export const parsePhoto = (file) => { return new Promise((resolve, reject) => { const reader = new FileReader();

我有一个对象,在不同的位置有嵌套的
文件
实例。我希望递归地遍历对象,检查对象是否是文件的
实例
,使用承诺从实例创建数据url,并仅在所有承诺都已解决时才解决承诺

我有一个现有函数,它返回一个承诺,并在文件中的数据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);
        }
    })
}
我有一个递归查找对象中
文件的函数

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;
}
我希望保留传递的对象的现有结构(
),并且仅用base64字符串替换文件实例

我也知道承诺。所有的承诺,但不确定如何在这种情况下使用它


当所有文件都转换为base64字符串时,如何将
convertPhotosToBase64
返回为解析的承诺?
承诺。所有的
都按照您的要求执行。在这种情况下使用它最简单的方法是在函数底部执行
return Promise.all(converted)
,它将返回一个特殊的Promise,直到参数中的所有Promise都已解决后才会解决。

让我们先简化一下函数,以减少所有这些条件的重复:

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
是异步的,并返回一个承诺。这意味着整个
convertPhotosToBase64
将需要变为异步并始终返回一个承诺。考虑到四种明显不同的情况,这实际上比听起来要简单:

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
?我知道
Promise.all
存在。你创建一个Promise数组,然后
从你的内部
处理程序返回Promise.all(promiseArray)
。然后()
处理程序。你真的需要它是base64吗?我必须将它存储在数据库中,所以是的。