如何在 onchange 函数中使用 promise 获取 json 的文件上传?

How to get json of file upload using promise in onchange function?

我构建了一个将表单转换为 json 的网站,但我需要将上传的图像文件转换为 base64(字符串)并添加到 json,但它只有 return 个 url,它在 console.log() 中成功,但在赋值时没有成功,这是我的代码

<form id="test" action="#" method="post">
    <div class="row">
        <div class="form-group">
            <label>First Name</label>
            <input name="namadepan" type="text" placeholder="Enter First Name Here.." class="form-control">
        </div>

    <div class="form-group">
        <label for="gambar">Foto</label>
        <input type="file"  class="form-control" name ="gambar" id="imagefile" value="Import"  onchange="toJSONString(document.getElementById('test'))" />
    </div>
    <p>
        <input type="submit" value="Send" class="btn btn-primary btn-block" />
    </p>
</form>

<textarea id="output"  class="form-control"></textarea>

这是脚本

function toJSONString(form) {
    var obj = {};
    var elements = form.querySelectorAll("input, select, textarea");
    for (var i = 0; i < elements.length; ++i) {
        var element = elements[i];
        var name = element.name;
        var value = element.value;

        if (element.type == "file") {
            var p = new Promise(function (resolve) {
                var reader = new FileReader();
                reader.onload = function () {
                    code = reader.result;
                    resolve(code);
                    console.log(reader.result);
                };
                reader.readAsDataURL(element.files[0]);
            });

            p.then(function (result) {
                value = result;
            })
        }

        if (name) {
            obj[name] = value;
        }
    }
    //return JSON.stringify( obj );
    document.getElementById("output").value = JSON.stringify(obj);
}

上面的结果是

{"namadepan":"johndoe","gambar":"C:\fakepath\t2.jpg"}

如我所料

{"namadepan":"johndoe","gambar":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAUDBAQEAwUE"}

C:\fakepath\t2.jpg 值来自 element.value

你看到这个是因为你在 promise 解决之前存储了值。

要正确等待promise,请看下面:

请注意 toJSONString 现在是一个 async 函数

async function toJSONString(form) {
    var obj = {};
    var elements = form.querySelectorAll("input, select, textarea");
    for (var i = 0; i < elements.length; ++i) {
        var element = elements[i];
        var name = element.name;

        // check `name`
        if(name) {
            // await the Promise here
            var value = await new Promise((resolve, reject) => {
                if (element.type == "file") {
                    var reader = new FileReader();

                    reader.onload = function () {
                        // resolve to data url
                        resolve(reader.result);
                    };
                    
                    reader.readAsDataURL(element.files[0]);
                } else {
                
                    // resolve to value
                    resolve(element.value);
                }
            });

            // store the value after the promise is resolved.
            obj[name] = value;
        }
        
    }
    //return JSON.stringify( obj );
    document.getElementById("output").value = JSON.stringify(obj);
}
<form id="test" action="#" method="post">
    <div class="row">
        <div class="form-group">
            <label>First Name</label>
            <input name="namadepan" type="text" placeholder="Enter First Name Here.." class="form-control">
        </div>

    <div class="form-group">
        <label for="gambar">Foto</label>
        <input type="file"  class="form-control" name ="gambar" id="imagefile" value="Import"  onchange="toJSONString(document.getElementById('test'))" />
    </div>
    <p>
        <input type="submit" value="Send" class="btn btn-primary btn-block" />
    </p>
</form>

<textarea id="output"  class="form-control"></textarea>