Use webworker para exportar excel

Exportar archivos de Excel es una función muy común durante el desarrollo de proyectos. De acuerdo con la forma de generar archivos de Excel, generalmente se divide en generación de back-end y generación de front-end.

Por lo general, hay dos formas para que el front-end descargue el Excel generado por el back-end. Una es que el back-end devuelve la dirección de descarga temporal del archivo de Excel y el front-end lo descarga directamente. La otra es que el back-end devuelve datos binarios de ArrayBuffer, que se descargan después de los procesos del front-end.

Es mucho más simple para el front-end generar Excel. El back-end solo necesita devolver datos JSON en un formato específico. El navegador del front-end completa el paso de generar Excel, lo que puede reducir en gran medida la presión sobre el servidor y ahorrar recursos del servidor. Sin embargo, cuando el front-end exporta una gran cantidad de datos en el hilo principal, excelinevitablemente bloqueará el hilo principal, lo que hará que la página se congele y afecte la experiencia del usuario ;

HojaJS

SheetJS, también conocido como XLSXJS, se llama SheetJS en el sitio web oficial. Admite navegadores, nodejs, deno y react-native, y los navegadores son compatibles con ie10+.

SheetJS Community Edition proporciona una solución de código abierto probada en batalla para extraer datos útiles de casi cualquier hoja de cálculo compleja y generar nuevas hojas de cálculo que se pueden usar con software heredado y moderno. --Extracto del sitio web oficial

Este es  十万行 20列 un ejemplo de datos exportados:

const cloLen = 20;
const rowLen = 100000;
const row = Array(cloLen).fill().reduce((t, e, i) => ({ ...t, [`字段${i + 1}`]: `字段${i + 1}的值` }), {});
const list = Array(rowLen).fill({ ...row });

const wb = XLSX.utils.book_new();
const ws = XLSX.utils.json_to_sheet(list, { dense: true });
XLSX.utils.book_append_sheet(wb, ws);
XLSX.writeFile(wb, `${new Date().toLocaleTimeString()}.xlsx`, {
  bookSST: true,
});

Debido a la naturaleza de subproceso único de JavaScript, una gran cantidad de operaciones de JS bloquearán el proceso de representación del navegador, lo que dará como resultado varios grados de animación suspendida del navegador.

Tomando mi mac pro como ejemplo, se tarda 十万行 20列entre 1700 y 1800 ms en generar un archivo de Excel, y el navegador también se congelará durante tanto tiempo. Este tiempo aumenta linealmente a medida que aumenta el número de filas y columnas.

En este momento, debe usar WebWorker para evitar el bloqueo de la representación del navegador.

const cloLen = 20;
const rowLen = 100000;
const row = Array(cloLen).fill().reduce((t, e, i) => ({ ...t, [`字段${i + 1}`]: `字段${i + 1}的值` }), {});
const list = Array(rowLen).fill({ ...row });

const SheetJSWebWorker = new Worker(
  URL.createObjectURL(
    new Blob([
      `
      importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js");
      onmessage = ({ data }) => {
        const wb = XLSX.utils.book_new();
        const ws = XLSX.utils.json_to_sheet(data, { dense: true });
        XLSX.utils.book_append_sheet(wb, ws);
        postMessage(XLSX.write(wb, { type: "array", bookType: "xlsx", bookSST: true, compression: true }))
      };
    `,
    ])
  )
);

SheetJSWebWorker.postMessage(list);
SheetJSWebWorker.onmessage = ({ data }) => {
  const a = document.createElement("a");
  a.download = `${new Date().toLocaleTimeString()}.xlsx`;
  a.href = URL.createObjectURL(
    new Blob([data], { type: "application/octet-stream" })
  );
  a.click();
};

En este momento, el tiempo de ejecución para generar Excel es de aproximadamente 2400 ~ 2500 ms. Pero la página se muestra sin ningún bloqueo.

Tenga en cuenta que SheetJS es un proyecto comercial. Estamos utilizando la edición comunitaria completamente gratuita. La edición comunitaria solo proporciona funciones muy limitadas, como generar Excel y combinar celdas. Si queremos personalizar el estilo de generación de Excel, necesitamos usar algunos periféricos de código abierto de SheetJS, como xlsx-style  y  xlsx-populate  . No me extenderé aquí, y cualquiera que esté interesado puede hacer su propia investigación.

Si desea exportar Excel con funciones personalizadas, debe usar ExcelJS para lograrlo.

ExcelJS

ExcelJS proporciona una función de Excel de exportación personalizada más potente, pero el rendimiento es solo una cuarta parte del de SheetJS.

Ejemplo de hilo único:

const cloLen = 20;
const rowLen = 100000;
const row = Array(cloLen).fill().reduce((t, e, i) => ({ ...t, [`字段${i + 1}`]: `字段${i + 1}的值` }), {});
const list = Array(rowLen).fill({ ...row });

const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet();
worksheet.columns = Object.keys(list[0]).map((e) => ({ header: e, key: e, width: 20 }));
worksheet.addRows(list);

const a = document.createElement("a");
a.download = `${new Date().toLocaleTimeString()}.xlsx`;
a.href = window.URL.createObjectURL(
  new Blob([await workbook.xlsx.writeBuffer()], {
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8",
  })
);
a.click();

Ejemplo de subprocesos múltiples:

const cloLen = 20;
const rowLen = 100000;
const row = Array(cloLen).fill().reduce((t, e, i) => ({ ...t, [`字段${i + 1}`]: `字段${i + 1}的值` }), {});
const list = Array(rowLen).fill({ ...row });

const ExcelJSWebWorker = new Worker(
  URL.createObjectURL(
    new Blob([
      `
      importScripts("https://cdn.bootcdn.net/ajax/libs/exceljs/4.3.0/exceljs.js");
      onmessage = async ({ data }) => {
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet();
        worksheet.columns = Object.keys(data[0]).map(e => ({ header: e, key: e, width: 20 }));
        worksheet.addRows(data);
        postMessage(await workbook.xlsx.writeBuffer())
      };
    `,
    ])
  )
);

ExcelJSWebWorker.postMessage(list);
ExcelJSWebWorker.onmessage = ({ data }) => {
  const a = document.createElement("a");
  a.download = `${new Date().toLocaleTimeString()}.xlsx`;
  a.href = window.URL.createObjectURL(
    new Blob([data], {
      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8",
    })
  );
  a.click();
};

CSV

La mayoría de las veces, los archivos de Excel que exportamos también se pueden generar en formato CSV.

Por el nombre, uno es para exportar CSV y el otro para exportar Excel.

Entonces, ¿cuál es la diferencia entre los dos?

Excel es una hoja de cálculo y guarda archivos en su propio formato patentado, xls o xlsx, que contiene información sobre todas las hojas de cálculo del libro.

CSV significa valores separados por comas, que es un formato de texto sin formato que separa por comas una serie de valores, pero no contiene formato, fórmulas, macros, etc.

En resumen, Excel no solo puede almacenar datos, sino también almacenar los resultados de la operación en los datos. El archivo CSV es solo un archivo de texto, solo almacena datos, por lo que es muy fácil de generar.

Al mismo tiempo, el documento CSV se muestra en forma de Excel de manera predeterminada después de abrirlo con Word, y solo se puede convertir a Excel mediante un procesamiento simple.

Ejemplo de hilo único:

const cloLen = 20;
const rowLen = 100000;
const row = Array(cloLen).fill().reduce((t, e, i) => ({ ...t, [`字段${i + 1}`]: `字段${i + 1}的值` }), {});
const list = Array(rowLen).fill({ ...row });

let str = Object.keys(list[0]).join() + "\n";
for (let i = 0; i < list.length; i++) {
  for (const key in list[i]) {
    str += `${list[i][key] + "\t"},`;
  }
  str += "\n";
}
const a = document.createElement("a");
a.href = "data:text/csv;charset=utf-8,\ufeff" + encodeURIComponent(str);
a.download = `${new Date().toLocaleTimeString()}.csv`;
a.click();

Ejemplo de subprocesos múltiples:

const cloLen = 20;
const rowLen = 100000;
const row = Array(cloLen).fill().reduce((t, e, i) => ({ ...t, [`字段${i + 1}`]: `字段${i + 1}的值` }), {});
const list = Array(rowLen).fill({ ...row });

const VanillaJSWebWorker = new Worker(
  URL.createObjectURL(
    new Blob([
      `
      importScripts("https://cdn.bootcdn.net/ajax/libs/exceljs/4.3.0/exceljs.js");
      onmessage = async ({ data }) => {
        let str = Object.keys(data[0]).join() + String.fromCharCode(10)
        for (let i = 0; i < data.length; i++) {
          for (const key in data[i]) {
            str += data[i][key] + '\t,';
          }
          str += String.fromCharCode(10);
        }
        postMessage('data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str))
      };
    `,
    ])
  )
);

VanillaJSWebWorker.postMessage(list);
VanillaJSWebWorker.onmessage = ({ data }) => {
  const a = document.createElement("a");
  a.download = `${new Date().toLocaleTimeString()}.csv`;
  a.href = data;
  a.click();
};

Resumir

La mayor ventaja de generar Excel en el front-end es que puede reducir el consumo de recursos del servidor, aprovechar al máximo los recursos de potencia informática del cliente y transferir la presión informática del servidor al navegador. cantidad de datos transmitidos es menor y relativamente más rápido.

Al mismo tiempo, las desventajas también son obvias. En primer lugar, JavaScript no es un lenguaje de programación con un alto rendimiento informático, y su rendimiento informático relativo no es tan bueno como el de la informática de servidor. En segundo lugar, el factor más importante que afecta la velocidad de generación del archivo de exportación depende del hardware del usuario, y las computadoras con un rendimiento diferente pueden tener una gran diferencia en la experiencia del usuario.

Los siguientes son escenarios generales aplicables de las soluciones anteriores, consulte:

  • Millones de datos utilizan CSV.
  • Las funciones sin estilo con gran cantidad de datos requieren SheetJS.
  • Una pequeña cantidad de datos es completamente funcional usando ExcelJS.
  • Grandes cantidades de datos requieren funcionalidad usando la versión comercial de SheetJS. 

Vínculos de documentación relacionada

 

Supongo que te gusta

Origin blog.csdn.net/qq_44376306/article/details/131271612
Recomendado
Clasificación