大数据导出真经

109 阅读3分钟

文/ 天机阁首席数据导出大师

(云海之巅,紫袍道人手持乾坤玉简,玉简中流淌着万千数据洪流)

"今日传授尔等大数据Excel导出大法。须知数据导出,如同百川归海,需因势利导方能化繁为简。且看这数据玉简——"


第一章:Excel导出境界

凝气期(基础导出)

// 简单JSON数据导出
function exportSimpleJSON(data) {
    const ws = XLSX.utils.json_to_sheet(data);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
    XLSX.writeFile(wb, "data.xlsx");
}

筑基期(大数据分页导出)

// 分页获取数据并导出
async function exportLargeData(total, pageSize = 10000) {
    const wb = XLSX.utils.book_new();
    let page = 1;
    
    while ((page - 1) * pageSize < total) {
        const data = await fetchData(page, pageSize);
        const ws = XLSX.utils.json_to_sheet(data);
        XLSX.utils.book_append_sheet(wb, ws, `Page${page}`);
        page++;
    }
    
    XLSX.writeFile(wb, "large_data.xlsx");
}

元婴期(流式导出)

// 使用Stream API处理百万级数据
async function streamExport(total) {
    const writer = new ExcelJS.stream.xlsx.WorkbookWriter({
        filename: 'huge_data.xlsx'
    });
    const sheet = writer.addWorksheet('Data');
    
    let count = 0;
    const batchSize = 10000;
    
    while (count < total) {
        const data = await fetchBatchData(count, batchSize);
        data.forEach(row => sheet.addRow(row));
        count += batchSize;
    }
    
    await writer.commit();
}

第二章:导出七式

第一式:开天辟地(初始化工程)

# 安装核心库
npm install xlsx exceljs file-saver --save

第二式:刻录道纹(表头配置)

// 复杂表头定义
const headers = [
    { header: "ID", key: "id", width: 10 },
    { header: "姓名", key: "name", width: 20 },
    { header: "销售额", key: "sales", width: 15 }
];

// 使用ExcelJS创建带样式的表头
const worksheet = workbook.addWorksheet("销售数据");
worksheet.columns = headers;
worksheet.getRow(1).font = { bold: true };

第三式:注入灵力(数据格式化)

// 数据预处理
function formatData(rawData) {
    return rawData.map(item => ({
        id: item.id,
        name: item.user.name,
        sales: ${(item.amount / 100).toFixed(2)}`,
        date: new Date(item.createdAt).toLocaleDateString()
    }));
}

第四式:时空穿梭(分页处理)

// 分页获取数据
async function fetchPaginatedData(url, total) {
    const results = [];
    const pageSize = 5000;
    let page = 1;
    
    while ((page - 1) * pageSize < total) {
        const res = await axios.get(url, {
            params: { page, size: pageSize }
        });
        results.push(...res.data);
        page++;
    }
    
    return results;
}

第五式:天眼通(进度监控)

// 导出进度显示
const progress = {
    total: 0,
    processed: 0,
    update() {
        const percent = (this.processed / this.total * 100).toFixed(1);
        console.log(`导出进度: ${percent}%`);
    }
};

// 在数据处理循环中
progress.total = totalCount;
data.forEach(item => {
    // 处理数据...
    progress.processed++;
    progress.update();
});

第六式:自定义道纹(样式定制)

// 使用ExcelJS设置复杂样式
const style = {
    font: { name: '微软雅黑', size: 11 },
    border: {
        top: { style: 'thin' },
        left: { style: 'thin' },
        bottom: { style: 'thin' },
        right: { style: 'thin' }
    }
};

worksheet.eachRow(row => {
    row.eachCell(cell => {
        cell.style = style;
        if (cell.value > 10000) {
            cell.font = { color: { argb: 'FFFF0000' }, bold: true };
        }
    });
});

第七式:渡劫飞升(Web Worker优化)

// 在Worker中处理大数据
const worker = new Worker('export.worker.js');
worker.postMessage({ action: 'export', data: hugeData });

worker.onmessage = (e) => {
    if (e.data.type === 'progress') {
        updateProgress(e.data.value);
    } else if (e.data.type === 'done') {
        saveAs(e.data.blob, 'data.xlsx');
    }
};

第三章:导出心法

"导出五要:
1️⃣ 分而治之(大数据分页处理)
2️⃣ 流式处理(避免内存溢出)
3️⃣ 样式美观(专业表格呈现)
4️⃣ 进度反馈(用户体验优化)
5️⃣ 异常处理(网络中断恢复)"

第四章:实战演练

基础导出

// 正确示例:使用SheetJS导出
function exportWithSheetJS(data) {
    const ws = XLSX.utils.json_to_sheet(data);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
    XLSX.writeFile(wb, "export.xlsx");
}

// 错误示例:直接导出百万条数据
function exportHugeData(data) {
    // 可能导致浏览器崩溃
    exportWithSheetJS(data);
}

高级导出

// 多Sheet分页导出
async function exportMultiSheet(total) {
    const wb = new ExcelJS.Workbook();
    const pageSize = 50000;
    let page = 1;
    
    while ((page - 1) * pageSize < total) {
        const data = await fetchPage(page, pageSize);
        const ws = wb.addWorksheet(`Page ${page}`);
        ws.columns = headers;
        data.forEach(item => ws.addRow(item));
        page++;
    }
    
    const buffer = await wb.xlsx.writeBuffer();
    saveAs(new Blob([buffer]), "multi_sheet.xlsx");
}

第五章:导出禁忌

魔道案例

// 错误:同步处理大数据
function syncExport(data) {
    // 阻塞主线程
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.json_to_sheet(data); // 百万数据直接处理
    XLSX.utils.book_append_sheet(wb, ws, "Data");
    XLSX.writeFile(wb, "blocking_export.xlsx");
}

// 错误:内存泄漏
let cache = [];
async function leakyExport() {
    cache = []; // 未释放旧数据
    cache = await fetchAllData(); // 加载全部数据
    exportWithSheetJS(cache);
}

正道解法

// 正确:流式处理大数据
async function streamExport(total) {
    const writer = new ExcelJS.stream.xlsx.WorkbookWriter({
        filename: 'stream_export.xlsx'
    });
    const sheet = writer.addWorksheet('Data');
    
    let offset = 0;
    const batchSize = 10000;
    
    while (offset < total) {
        const data = await fetchBatch(offset, batchSize);
        data.forEach(row => sheet.addRow(row));
        offset += batchSize;
    }
    
    await writer.commit();
}

(突然,玉简剧烈震动,导出进程卡死)

弟子:"师尊!导出百万数据时浏览器崩溃了!"

道人:"痴儿!定是未做分页处理。且看这招——"

道人掐诀念咒,虚空中浮现优化代码:

// 分块处理大数据
async function chunkedExport(total, chunkSize = 50000) {
    const wb = new ExcelJS.Workbook();
    const sheet = wb.addWorksheet('Data');
    
    for (let start = 0; start < total; start += chunkSize) {
        const end = Math.min(start + chunkSize, total);
        const data = await fetchRangeData(start, end);
        data.forEach(row => sheet.addRow(row));
        await new Promise(resolve => setTimeout(resolve, 0)); // 释放事件循环
    }
    
    const buffer = await wb.xlsx.writeBuffer();
    saveAs(new Blob([buffer]), "chunked_export.xlsx");
}

飞升天象:

当数据导出修炼至大乘期,可:

  • 导出千万级数据不卡顿
  • 生成专业级报表样式
  • 实现服务端直接流式导出
  • 支持复杂公式和图表

(道人化作数据流光,融入玉简之中,浮现最后箴言)

"记住,导出之道在于'化整为零'。如同庖丁解牛,既要掌控全局,也需专注细节......"

(玉简展开,化作《大数据导出真经》)

<真经展开,显现完整导出知识图谱> <第二元神显化:关注天机阁,解锁更多数据秘法>


核心难点解析

  1. 整体架构设计
graph TD
    A[后端] -->|分页数据| B[前端处理]
    B -->|流式写入| C[Excel文件]
    C --> D[(本地下载)]
  1. 性能优化方案
// 内存优化配置
const workbook = new ExcelJS.Workbook({
    useSharedStrings: true,  // 共享字符串节省内存
    useStyles: true          // 启用样式支持
});
  1. 服务端配合要点
// 分页API设计
router.get('/api/large-data', async (ctx) => {
    const { page = 1, size = 10000 } = ctx.query;
    const data = await Model.find()
        .skip((page - 1) * size)
        .limit(size);
    
    ctx.body = {
        data,
        total: await Model.countDocuments()
    };
});
  1. 异常处理机制
// 断点续导实现
let exportedCount = 0;
try {
    while (exportedCount < total) {
        const data = await fetchBatch(exportedCount, batchSize);
        // 处理数据...
        exportedCount += data.length;
        saveProgress(exportedCount); // 保存进度
    }
} catch (err) {
    console.error(`导出中断,已导出${exportedCount}条`);
    // 恢复时可从exportedCount继续
}
  1. 格式兼容方案
// 多格式导出适配
function exportAs(format, data) {
    switch (format) {
        case 'xlsx':
            return exportXLSX(data);
        case 'csv':
            return exportCSV(data);
        case 'pdf':
            return exportPDF(data);
        default:
            throw new Error('不支持的格式');
    }
}