簡體   English   中英

解決嵌套在對象內部的任何數量的Promise

[英]Resolve any number promises nested inside of an object

我有一個在各個位置都有嵌套File實例的對象。 我想遞歸地遍歷對象,檢查對象是否為instanceof Fileinstanceof 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM