Reading a 92 byte CSV file takes 15–20 seconds to process

I’m working on an Angular app and trying to read and parse a simple CSV file that is only 92 bytes. Surprisingly, the upload and processing takes around 15 to 20 seconds, even for such a tiny file.

Here’s the function I’m using:

upload() {
  const fileInput = document.createElement("input");
  fileInput.type = "file";
  fileInput.accept = ".csv";
  this.isLoading = true;

  fileInput.addEventListener("change", (event) => {
    const target = event.target as HTMLInputElement;
    if (target.files?.length) {
      const file = target.files[0];
      this.processUploadedFile(file);
    }
  });

  fileInput.click();
}

private processUploadedFile(file: File) {
  this.uploadedFileName = file.name;

  if (file.type === "text/csv" || file.name.endsWith(".csv")) {
    const reader = new FileReader();
    reader.onloadend = (e) => {
      const contents = e.target?.result as string;
      if (contents) {
        this.parseCSVData(contents);
      }
    };
    reader.readAsText(file);
  } else {
    this.toast.danger("Please upload a valid CSV file.");
  }
}

private parseCSVData(csvData: string) {
  const lines = csvData.split("\n").filter((line) => line.trim() !== "");
  const parsedData: Product[] = lines.slice(2).map((line, index) => {
    const values = line.split(";");
    return {
      position: index + 1,
      height: parseInt(values[0]) || 0,
      diameter: parseInt(values[1]) || 0,
      li: parseInt(values[2]) || 0,
      lt: parseInt(values[3]) || 0,
    };
  });

  if (parsedData.length) {
    this.dataSource = parsedData;
  }
  this.isLoading = false;
}
<button
   mat-flat-button
   aria-label="Upload data"
   (click)="upload()"
   >
   <mat-icon>upload</mat-icon>
   <span>Upload data</span>
</button>

I’ve tried:

  • Using FileReader.readAsText() as shown above
  • Switching to PapaParse, but the delay still happens
  • Confirmed the CSV file is only 92 bytes, with just 3 lines of simple numeric data
  • Verified the browser’s performance tab (no major CPU or memory usage)
  • Tried on different browsers (Chrome, Edge) — same result

CSV File

1 Like

Your code is logically sound, and reading such a tiny file via FileReader.readAsText() should complete almost instantly. Given that you’ve ruled out file size, CPU load, and even third-party libraries like PapaParse, here are some realistic causes and suggestions to investigate:


1. File Picker UI Blocking Angular Zone

You’re creating a native <input type="file"> dynamically and triggering .click() on it. While this is valid, some browsers can delay firing the change event (especially in complex Angular zones).

Try this fix:

Use Angular’s NgZone to run the file handling outside of Angular’s change detection:

constructor(private ngZone: NgZone) {}

upload() {
  const fileInput = document.createElement("input");
  fileInput.type = "file";
  fileInput.accept = ".csv";

  fileInput.addEventListener("change", (event) => {
    this.ngZone.run(() => {
      const target = event.target as HTMLInputElement;
      if (target.files?.length) {
        const file = target.files[0];
        this.isLoading = true;
        this.processUploadedFile(file);
      }
    });
  });

  fileInput.click();
}

2. Heavy Change Detection / Component Re-render

If this.dataSource = parsedData is bound to a heavy Angular material table (<mat-table>, <mat-paginator>), that can trigger expensive change detection and DOM re-rendering.

####Try this for performance isolation:

Temporarily comment out this line and time the CSV processing again:

// this.dataSource = parsedData;

If the upload becomes instant, the bottleneck is likely rendering or reactivity, not file reading.


3. Asynchronous Reader Delay

While FileReader.readAsText() is fast, the browser may not immediately prioritize its completion if the main thread is busy.

Try timing it:

reader.onloadend = (e) => {
  console.timeEnd("read");
  const contents = e.target?.result as string;
  if (contents) {
    this.parseCSVData(contents);
  }
};
console.time("read");
reader.readAsText(file);

This can help you isolate where the time is being spent.


4. Avoid Double Triggering of fileInput.click()

In some browsers, programmatically created inputs can behave inconsistently. Try moving the element creation into ngOnInit() or creating a persistent <input type="file" hidden> in the template instead.


5. Dev Mode Overhead

Angular in development mode performs extra change detection and checks (especially with zone.js). Try building your app with --configuration production:

ng build --configuration production

Or serve it like this:

ng serve --configuration production

6. Line Splitting Strategy

You split on \n and use .slice(2) — are you sure your file has a 2-line header? If not, you’re possibly skipping all or most data. Could that be causing excessive re-renders of an empty table?


7. Mobile Device or Older CPU?

You mentioned trying different browsers, but if this is on a low-end device or throttled network conditions (e.g., remote desktop, VM), even trivial file operations can be slow.


Bonus Tip: Use a console.time() Benchmark

Add timers like so to trace bottlenecks:

console.time("csv-processing");

reader.onloadend = (e) => {
  const contents = e.target?.result as string;
  if (contents) {
    console.time("parse");
    this.parseCSVData(contents);
    console.timeEnd("parse");
  }
  console.timeEnd("csv-processing");
};

Summary of Key Fixes:

Fix Description
NgZone.run() Avoid Angular zone blocking
Profile readAsText() Confirm it’s not slow
Avoid heavy UI re-render Comment out dataSource to test
Use production mode Avoid Dev overhead
Refactor file input Consider template-based input
Use timers Identify exact bottleneck