LearnNewsExamplesServices
Frontmatter
id8805
titleHarden Core Components against Async Destruction
stateClosed
labels
bugaicore
assigneestobiu
createdAtJan 19, 2026, 12:06 PM
updatedAtJan 19, 2026, 12:18 PM
githubUrlhttps://github.com/neomjs/neo/issues/8805
authortobiu
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJan 19, 2026, 12:18 PM

Harden Core Components against Async Destruction

Closed v11.23.0 bugaicore
tobiu
tobiu commented on Jan 19, 2026, 12:06 PM

Goal: Harden Core Framework Components against asynchronous destruction to prevent memory leaks and runtime errors when a component is destroyed while an async operation (fetch, XHR) is pending.

Scope:

  1. src/container/Base.mjs: Hardening loadItems().
  2. src/form/field/FileUpload.mjs: Hardening deleteDocument(), checkDocumentStatus() and upload() (XHR).
  3. src/component/Circle.mjs: Refactoring afterSetUrl to async/await + trap().
  4. src/component/Helix.mjs: Refactoring afterSetUrl to async/await + trap().

Implementation Details:

  • Use this.trap(promise) to wrap fetch or Neo.Xhr calls.
  • Ensure XHR based logic (FileUpload) handles destruction gracefully (aborting XHR, ignoring callbacks).
  • Consistent use of async/await over .then().
tobiu added the bug label on Jan 19, 2026, 12:06 PM
tobiu added the ai label on Jan 19, 2026, 12:06 PM
tobiu added the core label on Jan 19, 2026, 12:06 PM
tobiu referenced in commit 30acdd7 - "fix: Harden Core Components against Async Destruction (#8805)" on Jan 19, 2026, 12:17 PM
tobiu assigned to @tobiu on Jan 19, 2026, 12:18 PM
tobiu
tobiu Jan 19, 2026, 12:18 PM

Input from Gemini 3 Pro:

✦ I have hardened the core framework components against asynchronous destruction to prevent memory leaks and runtime errors.

Summary of Changes:

  1. src/container/Base.mjs:

    • Hardened loadItems() by wrapping fetch, response.json(), and dynamic imports with this.trap(). This ensures that if the container is destroyed while loading items, the operation is safely cancelled.
  2. src/form/field/FileUpload.mjs:

    • Wrapped fetch calls in deleteDocument() and checkDocumentStatus() with this.trap().
    • Implemented a destroy() method to explicitly abort any active XHR uploads (this.xhr.abort()).
    • Added checks for this.isDestroyed in all XHR event handlers (onUploadProgress, onUploadAbort, onUploadError, onUploadDone) to prevent execution on dead instances.
  3. src/component/Circle.mjs & src/component/Helix.mjs:

    • Refactored loadData() to use async/await.
    • Wrapped the Neo.Xhr.promiseJson() call with this.trap().
    • Added error handling to specifically suppress logging if the error is Neo.isDestroyed.

Verification:

I created and ran a comprehensive suite of Playwright unit tests to verify these fixes:

  • test/playwright/unit/container/AsyncLoadItems.spec.mjs: Verifies loadItems rejection on destruction.
  • test/playwright/unit/form/field/FileUploadAsync.spec.mjs: Verifies deleteDocument rejection on destruction.
  • test/playwright/unit/component/CircleAsync.spec.mjs: Verifies loadData rejection on destruction.

All 8 tests (including the core infrastructure tests) passed successfully.

tobiu closed this issue on Jan 19, 2026, 12:18 PM