webassembly/proxy_js: Promote Python thenable to a Promise.

Signed-off-by: Damien George <damien@micropython.org>
pull/14213/head
Damien George 2024-03-29 23:07:39 +11:00
rodzic 3997532186
commit 7c62fbe3f2
3 zmienionych plików z 55 dodań i 1 usunięć

Wyświetl plik

@ -89,7 +89,22 @@ function proxy_call_python(target, argumentsList) {
if (argumentsList.length > 0) {
Module._free(args);
}
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
const ret = proxy_convert_mp_to_js_obj_jsside_with_free(value);
if (ret instanceof PyProxyThenable) {
// In Python when an async function is called it creates the
// corresponding "generator", which must then be executed at
// the top level by an asyncio-like scheduler. In JavaScript
// the semantics for async functions is that they are started
// immediately (their non-async prefix code is executed immediately)
// and only if they await do they return a Promise to delay the
// execution of the remainder of the function.
//
// Emulate the JavaScript behaviour here by resolving the Python
// async function. We assume that the caller who gets this
// return is JavaScript.
return Promise.resolve(ret);
}
return ret;
}
function proxy_convert_js_to_mp_obj_jsside(js_obj, out) {

Wyświetl plik

@ -0,0 +1,31 @@
// Test using Python functions as JS callbacks.
const mp = await (await import(process.argv[2])).loadMicroPython();
globalThis.asyncTimeout = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms));
mp.runPython(`
import js
def f0():
print("f0 run")
async def f1():
print("f1 run")
async def f2():
print("f2 start")
await js.asyncTimeout(0)
print("f2 end")
async def f3():
print("f3 start")
await f2()
print("f3 end")
js.setTimeout(f0, 0)
js.setTimeout(f1, 50)
js.setTimeout(f2, 100)
js.setTimeout(f3, 150)
`);

Wyświetl plik

@ -0,0 +1,8 @@
f0 run
f1 run
f2 start
f2 end
f3 start
f2 start
f2 end
f3 end