将base64数据保存到变量中。

3

我看过几个例子,根据这些例子准备了我的解决方案。但是我仍然得到了 Promise __proto__: Promise [[PromiseStatus]]: "pending" [[PromiseValue]]: undefined 的错误信息。我正在尝试将我的 base64 数据存储在变量中,请告诉我我的代码有什么问题,并提供一个可行的解决方案。

以下是我尝试的代码:

import React, { Component } from 'react'
import { DropzoneArea, DropzoneDialog } from 'material-ui-dropzone'
import Button from '@material-ui/core/Button';


async function getBaseData(selectedFile) {
    let base64;
    var fileToLoad = selectedFile[0];
    base64 = await getBase64(fileToLoad);
    return base64; //This returns me PromiseStatus Pending
}

function getBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
        return Promise.resolve(reader.result)
    });
}

export class ImageUploader extends Component {
    constructor(props) {
        super(props);
        this.state = {
            files: [],
            image: null,
        };
    }
    handleImageChange(files) {
        const { imageCallback } = this.props
        imageCallback(getBaseData(files)); // By this callback i am trying to pass my base64 string to other component
    }
    render() {
        return (
            <DropzoneArea
                acceptedFiles={['image/*']}
                filesLimit={1}
                maxFileSize={10000000}
                //showPreviews={false}
                onChange={this.handleImageChange.bind(this)}
            />
        )
    }
}

3个回答

2
你的问题在于你如何管理你的Promise。根据文档,你不需要从Promise中返回任何东西,否则它将立即解决。
在这种情况下,当你执行以下操作时:
function getBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
        return Promise.resolve(reader.result) // <--- this is wrong.
    });
}

这段代码涉及到IT技术,它的翻译是:it will resolve to Promise.resolve(reader.result) which is undefined, because maybe it didn't finish, maybe and just maybe you could get an accurate result but it is just luck that the reader actually resolves before that return(race condition)。

通俗易懂来说,为了让代码正常工作,你需要使用promise的resolverrejecter来进行解决或拒绝。

编辑提示:注意在设置回调之前也要调用阅读器函数,如果先读取文件,再添加回调,那么这些回调就不会被调用。

最后,将代码更改成以下内容:

function getBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();

        //set the callbacks before reading the object
        reader.onload = () => resolve(reader.result); 
        reader.onerror = error => reject(error);

        reader.readAsDataURL(file);
    });
}

非常感谢@Prince Hernandez,尝试后我得到了Promise __proto__:Promise [[PromiseStatus]]:"resolved" [[PromiseValue]]:"",但是没有值。 - user2019
我已经尝试在调试模式下设置断点 resolve(reader.result),并且我得到了 Promise __proto__: Promise [[PromiseStatus]]: "resolved" [[PromiseValue]]: "data:image/png;base64,iVBO... 但是在非调试模式下,PromiseValue为空。请问有什么建议吗? - user2019
抱歉,您的代码还有另一个问题,让我编辑问题并添加正确的步骤。 - Prince Hernandez

1
问题在于getBaseData是一个异步函数,但你仍然需要等待它解析。

尝试像这样“等待”它:

handleImageChange(files) {
            const { imageCallback } = this.props;
            async function wrap(){
               const result = await getBaseData(files); //result should be a value here and not promise
               imageCallback(result);
            }
            wrap(); // call the async function which will await the getBaseData and use your callback

        }

感谢@Vladimir Bogomolov的帮助,我已经尝试了这种方式,我已经按照@PrinceHernandez的建议更改了我的function getBase64(file),并且完全按照以下方式更改了我的处理程序`handleImageChange(files) { const { imageCallback } = this.props; async function wrap(){ const result = await getBaseData(files); imageCallback(result); } wrap(); }`但是在我的回调函数中,我得到了一个空字符串的结果。请告诉我我犯了什么错误。 - user2019
保留您的函数getBase64不变。我已经使用您的代码和我的修改进行了测试,它可以正常工作。 - Vladimir Bogomolov
不需要等待Promise解决,只需使用.then(imageCallback)链接它。 - darksmurf

0
这里有两个问题:创建Promise的方式不正确,而且你没有按照应该的方式处理已解决的Promise。没有必要像其他答案建议的那样使用任何asyncawaitPromise的创建方式:
function getBaseData(selectedFiles) {
    var fileToLoad = selectedFiles[0];
    return getBase64(fileToLoad);
}

function getBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result); 
        reader.onerror = error => reject(error);
        reader.readAsDataURL(file);
    });
}

解决 Promise:
handleImageChange(files) {
    const { imageCallback } = this.props
    getBaseData(files).then(imageCallback);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接