diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs index d2d4ee92c057a0..49063ad5e76e67 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using System.Threading; using Xunit; #pragma warning disable xUnit1026 // Theory methods should use all of their parameters @@ -31,6 +32,19 @@ public async Task MultipleImportAsync() Assert.Same(instance1, instance2); } + [Fact] + public async Task CancelableImportAsync() + { + var cts = new CancellationTokenSource(); + var exTask = Assert.ThrowsAsync(async () => await JSHost.ImportAsync("JavaScriptTestHelper", "./JavaScriptTestHelper.mjs", cts.Token)); + cts.Cancel(); + var actualEx2 = await exTask; + Assert.Equal("OperationCanceledException", actualEx2.Message); + + var actualEx = await Assert.ThrowsAsync(async () => await JSHost.ImportAsync("JavaScriptTestHelper", "./JavaScriptTestHelper.mjs", new CancellationToken(true))); + Assert.Equal("OperationCanceledException", actualEx.Message); + } + [Fact] public unsafe void GlobalThis() { diff --git a/src/mono/wasm/runtime/invoke-js.ts b/src/mono/wasm/runtime/invoke-js.ts index 72941f70de827f..85c1db588554ca 100644 --- a/src/mono/wasm/runtime/invoke-js.ts +++ b/src/mono/wasm/runtime/invoke-js.ts @@ -13,6 +13,7 @@ import { mono_wasm_new_external_root } from "./roots"; import { mono_wasm_symbolicate_string } from "./logging"; import { mono_wasm_get_jsobj_from_js_handle } from "./gc-handles"; import { endMeasure, MeasuredBlock, startMeasure } from "./profiler"; +import { wrap_as_cancelable_promise } from "./cancelable-promise"; const fn_wrapper_by_fn_handle: Function[] = [null];// 0th slot is dummy, we never free bound functions @@ -317,7 +318,7 @@ export function get_global_this(): any { export const importedModulesPromises: Map> = new Map(); export const importedModules: Map> = new Map(); -export async function dynamic_import(module_name: string, module_url: string): Promise { +export function dynamic_import(module_name: string, module_url: string): Promise { mono_assert(module_name, "Invalid module_name"); mono_assert(module_url, "Invalid module_name"); let promise = importedModulesPromises.get(module_name); @@ -328,13 +329,16 @@ export async function dynamic_import(module_name: string, module_url: string): P promise = import(/* webpackIgnore: true */module_url); importedModulesPromises.set(module_name, promise); } - const module = await promise; - if (newPromise) { - importedModules.set(module_name, module); - if (runtimeHelpers.diagnosticTracing) - console.debug(`MONO_WASM: imported ES6 module '${module_name}' from '${module_url}'`); - } - return module; + + return wrap_as_cancelable_promise(async () => { + const module = await promise; + if (newPromise) { + importedModules.set(module_name, module); + if (runtimeHelpers.diagnosticTracing) + console.debug(`MONO_WASM: imported ES6 module '${module_name}' from '${module_url}'`); + } + return module; + }); }