[browser] make dynamic import cancelable (#80257)
authorPavel Savara <pavel.savara@gmail.com>
Fri, 6 Jan 2023 20:18:17 +0000 (21:18 +0100)
committerGitHub <noreply@github.com>
Fri, 6 Jan 2023 20:18:17 +0000 (21:18 +0100)
* make dynamic import cancelable
* feedback

src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs
src/mono/wasm/runtime/invoke-js.ts

index d2d4ee9..49063ad 100644 (file)
@@ -5,6 +5,7 @@ using System.Collections.Generic;
 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
 
@@ -32,6 +33,19 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         }
 
         [Fact]
+        public async Task CancelableImportAsync()
+        {
+            var cts = new CancellationTokenSource();
+            var exTask = Assert.ThrowsAsync<JSException>(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<JSException>(async () => await JSHost.ImportAsync("JavaScriptTestHelper", "./JavaScriptTestHelper.mjs", new CancellationToken(true)));
+            Assert.Equal("OperationCanceledException", actualEx.Message);
+        }
+
+        [Fact]
         public unsafe void GlobalThis()
         {
             Assert.Null(JSHost.GlobalThis.GetPropertyAsString("dummy"));
index 72941f7..85c1db5 100644 (file)
@@ -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[] = <any>[null];// 0th slot is dummy, we never free bound functions
 
@@ -317,7 +318,7 @@ export function get_global_this(): any {
 export const importedModulesPromises: Map<string, Promise<any>> = new Map();
 export const importedModules: Map<string, Promise<any>> = new Map();
 
-export async function dynamic_import(module_name: string, module_url: string): Promise<any> {
+export function dynamic_import(module_name: string, module_url: string): Promise<any> {
     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;
+    });
 }