jquery 在等待完成之前执行“then”

gjmwrych  于 2023-02-15  发布在  jQuery
关注(0)|答案(1)|浏览(125)

我正在做一个项目,我需要一个表单。我想通过 AJAX 将数据发送到后端。我有一个文件上传,我需要将文件转换为base64,这样我就可以将其保存到我的数据库中。我使用FileReader在jQuery中转换文件。问题是,即使我添加了Promise()和await/async,我的 AJAX 函数也会在文件转换之前执行。我知道我做错了什么,但我不明白是什么。
有人能帮忙吗,我弄不好。谢谢!
这是我在控制台中得到的。你可以看到,文件在 AJAX 函数之后被记录,并且文件元素不在发送到后端的数据日志中。x1c 0d1x
我的ajax.js文件

$(document).ready(function () {
    $("form").submit(async function (e) {
        e.preventDefault();

        var children = $(this).find("input, textarea");
        console.log($(children).length);

        var nodeId = $(this).attr("data-nodeId");

        await loopChildren(children).then((allData) => ajaxCall(allData, nodeId))
    })
});

function loopChildren(children) {
    return new Promise((resolve) => {
        var allData = [];

        $(children).each(async function (index, elem) {
            var dataType = getDataType($(elem).attr("type"));

            await getContent(elem).then(function (content) {
                console.log("content " + index + " :" + content);
                allData.push({ "nodeId": parseInt($(elem).attr("id")), "content": content, "dataType": dataType });
            });
        })

        resolve(allData);
    })
}

function getContent(elem) {
    return new Promise(async (resolve) => {
        if ($(elem).attr("type") == "checkbox" || $(elem).attr("type") == "radio") {
            resolve($(elem).is(":checked"));
        }
        else if ($(elem).attr("type") == "file") {
            for (var file of $(elem)[0].files) {
                await processFile(file).then(function (e) {
                    resolve(e)
                });
            }
        }
        else {
            resolve($(elem).val());
        }
    })
}

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

        reader.onload = () => {
            resolve(reader.result);
        };

        reader.onerror = reject;

        reader.readAsDataURL(file);
    })
}

function processFile(file) {
    return new Promise(async (resolve, reject) => {
        try {
            await readFileAsync(file).then(function(content) {
                console.log(content);
                resolve(content);
            });
        } catch (err) {
            console.log(err);
            reject(err);
        }
    })
}

function ajaxCall(myVeryOwnDataObject, nodeID) {
    console.log(JSON.stringify(myVeryOwnDataObject));
    $.ajax({
        type: "POST",
        url: "/Umbraco/Api/Form/SendForm",
        contentType: "application/json; charset=utf-8",
        headers: { 'nodeId': nodeID },
        data: JSON.stringify(myVeryOwnDataObject),
        success: function (success) {
            console.log(success);
        },
        error: function (error) {
            console.log(error);
        }
    })
}

function getDataType(element) {
    switch (element) {
        case "text":
            return "text"
            break;
        case "textarea":
            return "textarea"
            break;
        case "number":
            return "number"
            break;
        case "email":
            return "text"
            break;
        case "tel":
            return "text"
            break;
        case "url":
            return "text"
            break;
        case "color":
            return "text"
            break;
        case "range":
            return "number"
            break;
        case "date":
            return "date"
            break;
        case "datetime-local":
            return "dateTime"
            break;
        case "month":
            return "date"
            break;
        case "time":
            return "time"
            break;
        case "file":
            return "file"
            break;
        case "checkbox":
            return "check"
            break;
        case "radio":
            return "check"
            break;
    }
}
cqoc49vn

cqoc49vn1#

loopChildren函数存在问题。
尽管在getContent调用之前有一个await,但这个承诺基本上被放弃了,因为在创建它的异步函数上没有任何await
此函数的执行方式为:

  • 创造一个新的承诺
  • 声明名为allData的变量
  • 循环children中的每个元素,并为每个元素创建一个异步函数
  • allData的值解析Promise,该值是空数组,因为我们没有对.each循环的结果执行await

为了解决这个问题,我将使用.map而不是.each,以便将children的每个元素Map到一个Promise中。然后我将使用Promise.all等待 * 所有 * 这些Promise的解析。我们可以直接从loopChildren返回Promise.all,并删除new Promise
函数变为:

function loopChildren(children) {
  const getContentPromises = $(children).map(function (index, elem) {
    var dataType = getDataType($(elem).attr("type"));

    return getContent(elem).then(content => {
      return {
        "nodeId": parseInt($(elem).attr("id")),
        "content": content,
        "dataType": dataType
      };
    });
  });

  return Promise.all(getContentPromises);
}

我创建了一个fiddle,它模拟了Promise解决方案的流程。

相关问题