6

我正在尝试从使用 sheet js 库加载的一组数据中编写多个 csv 文件。我的第一次尝试是这样的:

    for (let i = 0; i < dataSetDivided.length; i++) {
      let exportSet = dataSetDivided[i]
      console.log(exportSet)
      let ws = XLSX.utils.json_to_sheet(exportSet, {header: finalHeaders})
        let wb = XLSX.utils.book_new()
        XLSX.utils.book_append_sheet(wb, ws, "SheetJS")

      let todayDate = this.returnFormattedDate()

      let originalFileName = this.state.fileName
      let exportFileName = 'import_' + originalFileName + '_' + todayDate + '(part_' + (i + 1) + ').csv'

      XLSX.writeFile(wb, exportFileName)
}

我猜这个代码只写了一些文件,因为 for 循环在继续之前不会等待文件被写入。

所以我试图在如下承诺中编写每个文件:

Promise.all(
  dataSetDivided.map((exportSet, i) => {
    return new Promise((resolve, reject) => {

      console.log(exportSet)
      let ws = XLSX.utils.json_to_sheet(exportSet, {header: finalHeaders})
      let wb = XLSX.utils.book_new()
      XLSX.utils.book_append_sheet(wb, ws, "SheetJS")

      let todayDate = this.returnFormattedDate()

      let originalFileName = this.state.fileName
      let exportFileName = 'import_' + originalFileName + '_' + todayDate + '(part_' + (i + 1) + ').csv'

      XLSX.writeFile(wb, exportFileName, (err) => {
        if (err) {
          console.log(err)
          reject(err)
        } else {
          console.log('Created ' + exportFileName)
          resolve()
        }
      })
    })
  })
)
.then(() => {
  console.log('Created multiple files successfully')
})
.catch((err) => {
  console.log('ERROR: ' + err)
})

但是......这不起作用,再次只写入一些文件并且没有任何内容记录到控制台。谁能给我任何想法如何使这项工作或更好的方法来实现编写这样的多个文件的目标?有一个 XLSX.writeFileAsync 方法,但我找不到任何关于它如何工作的示例,我不确定这是否是我需要的。

带着感谢,

詹姆士

更新:

我现在正在使用 setTimeout 来延迟下一次 writeFile 调用......这适用于我的测试用例,但我知道这不是一个好的解决方案,当文件成功写入时有一个回调会更好:

    writeFileToDisk(dataSetDivided, i) {

    if (dataSetDivided.length > 0) {

      let exportSet = dataSetDivided[0]
      let ws = XLSX.utils.json_to_sheet(exportSet, {header: finalHeaders})
        let wb = XLSX.utils.book_new()
        XLSX.utils.book_append_sheet(wb, ws, "SheetJS")

      let todayDate = this.returnFormattedDate()

      let originalFileName = this.state.fileName
      let exportFileName = 'import_' + originalFileName + '_' + todayDate + '(part_' + i + ').csv'

      XLSX.writeFile(wb, exportFileName)

      dataSetDivided.splice(0, 1)

      i += 1

      setTimeout(() => {this.writeFileToDisk(dataSetDivided, i)}, 2500)
    }
  }

  this.writeFileToDisk(dataSetDivided, 1)

任何关于如何在不模拟文件写入时间的情况下使其工作的建议将不胜感激。

4

3 回答 3

8

我刚刚尝试了这个(第一次)XLSX 代码,并且可以确认它编写了预期的工作簿并同步运行......

'use strict'

const XLSX = require('xlsx');

let finalHeaders = ['colA', 'colB', 'colC'];
let data = [
    [ { colA: 1, colB: 2, colC: 3 }, { colA: 4, colB: 5, colC: 6 }, { colA: 7, colB: 8, colC: 9 } ],
    [ { colA:11, colB:12, colC:13 }, { colA:14, colB:15, colC:16 }, { colA:17, colB:18, colC:19 } ],
    [ { colA:21, colB:22, colC:23 }, { colA:24, colB:25, colC:26 }, { colA:27, colB:28, colC:29 } ]
];

data.forEach((array, i) => {
    let ws = XLSX.utils.json_to_sheet(array, {header: finalHeaders});
    let wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, "SheetJS")
    let exportFileName = `workbook_${i}.xls`;
    XLSX.writeFile(wb, exportFileName)
});

运行它会产生 workbook_0.xls、workbook_1.xls 和 workbook_2.xls,每个都有一个名为“SheetJS”的工作表。它们在 excel 中看起来都不错,例如,workbook_0 有...

在此处输入图像描述

我认为您应该异步进行写作,并建议对上述内容进行以下改编...

function writeFileQ(workbook, filename) {
    return new Promise((resolve, reject) => {
        // the interface wasn't clearly documented, but this reasonable guess worked...
        XLSX.writeFileAsync(filename, workbook, (error, result) => {
            (error)? reject(error) : resolve(result);
        })
    })
}


let promises = data.map((array, i) => {
    let ws = XLSX.utils.json_to_sheet(array, {header: finalHeaders});
    let wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, "SheetJS")
    let exportFileName = `workbook_${i}.xls`;
    return writeFileQ(wb, exportFileName)
});

Promise.all(promises).then(result => console.log(result)).catch(error => console.log(error));

运行这个异步代码,我发现它产生了相同的预期结果并且是异步的。

因此,您的原始循环看起来正确,并且应该同步工作。您没有得到预期结果的事实必须是由时间以外的其他原因引起的(或者可能是由反应引起的一些时间问题?)。

无论如何,如果您确实想使用我强烈推荐的异步方法,我已经展示了如何做到这一点(但我担心这可能无法完全解决问题,除非您在第一次尝试时弄清楚发生了什么)。

于 2018-04-13T17:42:50.043 回答
0

XLSX.writeFileAsync 确实有一个具有以下语法的回调。

xlsx.writeFileAsync(workbookName, workbook, (err) => {
   // It's a callback
});

但这只会处理异步写入一个文件。

您的情况很典型,如果您想做一系列事情,其中​​每个项目都是异步的,那么您不应该只使用循环/map/forEach 之类的迭代方法。

我建议的一个最好的库是“异步”。'async.parallel' 函数,它接受一组异步执行的函数,并在所有函数完成后调用回调。

https://caolan.github.io/async/docs.html#parallel

于 2019-04-26T07:11:28.210 回答
0

如果关注的是异步使用库而不阻塞服务器,您应该知道这个库实现似乎是同步的,您应该查看库的服务器演示自述文件,因为它有几个解决这个问题的建议:https:// github.com/SheetJS/sheetjs/tree/master/demos/server

于 2021-01-26T17:43:40.643 回答