You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

html2pdf.js异步批量生成PDF后结果展示异常求助

批量异步生成PDF后展示文件列表的问题修复

我正在尝试用html2pdf.js以异步方式批量生成PDF文件,目前PDF生成功能正常,但希望所有文件生成完成后,在div.alert元素中展示生成的文件列表及其访问路径,并隐藏加载状态。我写了如下代码但存在问题,恳请帮忙排查修复:

var envLabSub = ['env1', 'env2'];

//call function to convert in PDF
convertToPdf(msg, subject);

function convertToPdf(msg, subject) {
    envLabSub.forEach(async env => {
        await printer(msg, subject, env);
    })
        var message = "<h3><span class='glyphicon glyphicon-warning-sign' aria-hidden='true'></span> Email was sent with success !!</h3>";

    $("div.alert").removeClass().addClass('alert alert-success').html(message);
    $("div.alert").append("<ul></ul>");
    
    returArray.forEach(function (pdf) {
        $("div.alert ul").append("<li>File :<b>" + pdf.fileName + "</b> was created with success<br><a href='" + pdf.path + "' target='_blank'>" + pdf.path + "</a></ii>");
    });
    
    $("div.alert").show();
    $(".loading").hide();
}

async function printer(msg, subject, env) {

    var divToPrint = $('<div/>').append(msg);
    var versionTarget = $('#inpTargetVersion').val();
    var service = $('#Select_Service option:selected').text();
    var returArray = [];

    // date export Csv
    var MyDate = new Date();
    var datePdf = MyDate.getFullYear() + "-" + ('0' + (MyDate.getMonth()+1)).slice(-2) + "-" + ('0' + MyDate.getDate()).slice(-2) + "_" + ('0' + MyDate.getHours()).slice(-2) + ('0' + MyDate.getMinutes()).slice(-2) + ('0' + MyDate.getSeconds()).slice(-2);
    var fileName = datePdf + "_" + env.replace('/','_').trim() + "_" + service.trim() + "_" + versionTarget + ".pdf";
    
    var worker = html2pdf();
    await worker.from(divToPrint[0]);
    let myPdf = await worker.outputPdf('datauristring', 'mypdf.pdf');
  
    //this converts the uri to blob
    var preBlob = dataURItoBlob(myPdf);
    var file = new File([preBlob], fileName, {type: 'application/pdf'});
   
    // sends the message to api
    sendFile(file);
}

async function sendFile(userFiles) {
    let filePaths;
    let formData = new FormData();
    formData.append("filePdf", userFiles);
    let response = await fetch('views/ajax_response.php', {
        method: 'POST',
        body: formData
    });
        
    filePaths = await response.json();
    return filePaths;
}

function dataURItoBlob(dataURI) {
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
    else
        byteString = unescape(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    return new Blob([ia], {type:mimeString});
}

问题排查

  • forEach异步无效:forEach不会等待内部异步函数执行完成,导致UI更新代码在所有PDF生成前就已运行,此时没有文件数据。
  • 变量作用域错误:printer内的returArray是局部变量,外部convertToPdf无法访问;且未收集sendFile返回的路径信息。
  • 未返回异步结果:printer函数调用sendFile后未返回结果,无法收集每个文件的路径。
  • UI更新时机错误:原代码未等待所有异步任务完成就更新UI,导致列表为空。

修复后的代码

var envLabSub = ['env1', 'env2'];

// 调用PDF转换函数
convertToPdf(msg, subject);

// 改为异步函数,等待所有任务完成
async function convertToPdf(msg, subject) {
    // 用Promise.all等待所有printer任务完成,收集结果
    const fileResults = await Promise.all(
        envLabSub.map(env => printer(msg, subject, env))
    );

    // 更新UI
    var message = "<h3><span class='glyphicon glyphicon-warning-sign' aria-hidden='true'></span> 所有PDF生成完成 !!</h3>";
    $("div.alert").removeClass().addClass('alert alert-success').html(message);
    const $list = $("<ul></ul>").appendTo("div.alert");
    
    fileResults.forEach(function (pdf) {
        $list.append(`<li>文件 :<b>${pdf.fileName}</b> 生成成功<br><a href='${pdf.path}' target='_blank'>${pdf.path}</a></li>`);
    });
    
    $("div.alert").show();
    $(".loading").hide();
}

async function printer(msg, subject, env) {
    var divToPrint = $('<div/>').append(msg);
    var versionTarget = $('#inpTargetVersion').val();
    var service = $('#Select_Service option:selected').text();

    // 生成文件名
    var MyDate = new Date();
    var datePdf = MyDate.getFullYear() + "-" + ('0' + (MyDate.getMonth()+1)).slice(-2) + "-" + ('0' + MyDate.getDate()).slice(-2) + "_" + ('0' + MyDate.getHours()).slice(-2) + ('0' + MyDate.getMinutes()).slice(-2) + ('0' + MyDate.getSeconds()).slice(-2);
    var fileName = datePdf + "_" + env.replace('/','_').trim() + "_" + service.trim() + "_" + versionTarget + ".pdf";
    
    // 生成PDF
    var worker = html2pdf();
    await worker.from(divToPrint[0]);
    let myPdf = await worker.outputPdf('datauristring', 'mypdf.pdf');
  
    // 转换为Blob并创建File对象
    var preBlob = dataURItoBlob(myPdf);
    var file = new File([preBlob], fileName, {type: 'application/pdf'});
   
    // 上传文件并获取路径,返回文件名和路径的对象
    const filePath = await sendFile(file);
    return { fileName, path: filePath };
}

async function sendFile(userFiles) {
    let formData = new FormData();
    formData.append("filePdf", userFiles);
    let response = await fetch('views/ajax_response.php', {
        method: 'POST',
        body: formData
    });
        
    return await response.json();
}

function dataURItoBlob(dataURI) {
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
    else
        byteString = unescape(dataURI.split(',')[1]);

    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    return new Blob([ia], {type:mimeString});
}

修复说明

  • 将convertToPdf改为异步函数,使用Promise.all配合map替代forEach,确保所有PDF生成任务完成后再执行UI更新。
  • printer函数返回包含文件名和路径的对象,收集到fileResults数组中。
  • 移除无效的局部returArray变量,改用全局收集任务结果。
  • 调整UI更新逻辑,确保在所有文件生成并获取路径后再渲染列表。

内容的提问来源于stack exchange,提问作者Jean-Philippe SANTOS DE JESUS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 04:14:55