Repository: electron
Issue: "Object has been destroyed at DownloadItem" error occurs when downloading
Labels: platform/macOS,bug :beetle:,status/confirmed,32-x-y,33-x-y,34-x-y

### Preflight Checklist

- [x] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [x] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [x] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a bug report that matches the one I want to file, without success.

### Electron Version

32.1.2

### What operating system(s) are you using?

macOS

### Operating System Version

macOS monterey 12.5.1

### What arch are you using?

arm64 (including Apple Silicon)

### Last Known Working Electron version

_No response_

### Expected Behavior

![Image](https://github.com/user-attachments/assets/4e155aee-ac29-4d81-b78e-6f18b5dac5ba)

While downloading an item, if the electron application closes, sometimes "Object has been destroyed" error occurs.
This error message should always not open.

### Actual Behavior

This error occurs in rare cases(in my experience, with a nearly 1% chance).
You can reproduces this error by executing the [below git url](https://github.com/mochang2/object-has-been-destroyed-poc) after commenting out 44\~49th lines of `src/main.ts`.    
(I've automated the action with `run.sh `, so it will happen if you run that shell script a several times)
The way to run into the error in certain(in 100%) is to remove comment 44\~49th lines of `src/main.ts`, which adds a long synchronous action in an "updated" event listener of `DownloadItem`.

In my opinion, this error occurs if the following situation is:

1. "updated" event emit

```cc
// electron_api_download_item.cc
void DownloadItem::OnDownloadUpdated(download::DownloadItem* item) {
  if (!CheckAlive())
    return;
  if (download_item_->IsDone()) {
    Emit("done", item->GetState());
    Unpin();
  } else {
    Emit("updated", item->GetState());
  }
}
```

2. Even if window(can get by `BrowserWindow.getFocusedWindow()`) is destroyed, callbacks in the callback queue remains.

3. "updated" event on

```ts
// main.ts
item.on("updated", () => {
  for (let i = 0; i < 1_000_000_000; i++) {
    // a long synchronous task
    if (i % 200_000_000 === 0) {
      console.log(i, window.isDestroyed());
    }
  }
  console.log(window.isDestroyed());
  console.log("updated", window.webContents.isDestroyed()); // error point!!
});
```

Currently, the only way to prevent errors seems to be the following.

1. `try-catch`

```ts
// main.js
item.on("updated", () => {
  try {
    // ...
    console.log("updated", window.webContents.isDestroyed());
  } catch (error) {
    console.error(error);
  }
});
```

2. `if`

```ts
// main.ts
item.on("updated", () => {
  if (window?.webContents) {
    // ...
    console.log("updated", window.webContents.isDestroyed());
  };
});
```

However, the above solution doesn't seem to be good because all event listers need these exceptions or error handling logic.
This is also the case in that the event listener has to pay attention to whether the window has been destroyed.

Can you develop a better way for this error?


### Testcase Gist URL

https://github.com/mochang2/object-has-been-destroyed-poc

### Additional Information

For the first time, I found this error message in Windows 10 and Electron 22.3.8.  
As MacOS with Electron 32.1.2 also encounters this error, I think this bug happens regardless of OS or electronic version.