Closed Faless closed 3 years ago
Just throwing an idea out there: Could promises be represented in Godot-land as resumable function state? If so, users could use yield
/await
syntax to wait for the resolution of a promise.
The returned value could be some special JavascriptPromiseResult object that contains a status
property that is !=OK
if the promise is rejected, and a value
property that contains the value the promise was resolved/rejected with.
To specifically address the issue of the promise potentially rejecting before catch
is called: If the promise rejects and no catch had been called, note the rejection down. When catch is called, check if the promise has been rejected before and invoke the catch callback if so (and potentially clear the noted rejection to prevent multiple invocations of catch callbacks).
@MickeMakaron I had originally thought about having a specialized JavascriptPromiseResult
, but I fear the more we try to interpret results programmatically the more dangerous it is as many libraries relies on overriding, monkey patching and polyfills.
Additionally, the function state is not really a concept that exists in Godot (only in gdscript).
But I totally agree that using yield/await for promises would be great, so maybe the API could be adjusted this way:
Instead of is_promise
the method will be as_promise
, which returns another JavaScriptObject that will emit completed
(with the result) when the Promise resolves or rejects.
var req = axios.call("get", "/user?ID=12345")
var result = await req.as_promise().completed
if result.error:
print("Error: ", result.as_variant())
else:
print(result.as_variant())
What do you think?
@Faless Sounds good!
Would it be possible to allow the user to await the return value without
as_promise
? I.e.
var result = await axios.call("get", "/user?ID=12345").completed
Or maybe that's still risky, as you said?
I guess that would require something along these lines?
completed
signal.completed
immediately?).If doing the above on every call comes with issues, maybe it could be done sneakily only when the completed
property is get
ed by the user. 😅
only when the
completed
property isget
ed by the user. sweat_smile
I don't think this is possible.
Or maybe that's still risky, as you said?
I fear it might still be risky, but it could actually work, since we'll have to try/catch anyway.
It would be wasteful cases where the user registers a then
callback, but hey, JavaScript is all about being wasteful so that's okay :smile_cat:
Will it be possible to call GdScript functions from javascript by registering methods via e.g. JavaScript.add_interface
? I noticed you mention godotengine/godot-proposals#286 but you don't mention js->gd interop.
You don't really need that method, because you can call JavaScript.get_interface("my handler").call("register_callback", cb) to register callback that can be called from JS
On Fri, Nov 20, 2020, 07:26 Mikael Hernvall notifications@github.com wrote:
Will it be possible to call GdScript functions from javascript by registering methods via e.g. JavaScript.add_interface? I noticed you mention godotengine/godot-proposals#286 https://github.com/godotengine/godot-proposals/issues/286 but you don't mention gd->js interop.
Sonething I've noticed being asked about numerous times in various Godot forums is how to call a GDScript function from JavaScript.
Since you're already in the process of making engine.addInterface, would it be possible to also add a JavaScript.add_interface,
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot-proposals/issues/1852#issuecomment-730881615, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAM4C3RTYYM5OAF5OEE7TATSQYDYNANCNFSM4TYX32TQ .
In C# we have Task
object that would perfectly mapped to js Promise
. for GDScript you should also adopt this system as you like. You should also introduce async
/await
into your language
And for callback you should adopt Observable
and reactive extension paradigm (which also align with my godotengine/godot-visual-script#20). There was also streaming paradigm, IAsyncEnumerable
and operator like await foreach
in C# that you could also considered
There are https://github.com/WebAssembly/reference-types support for WASM to allow get and pass reference from JS around in WASM system. It would make interop with js more natural if we have support for it in C#
@Thaina: It's the proposal, I don't think it's gone anywhere yet.
@Zireael07 It was already supported in some browser. At least firefox since 79. I am quite sure it supported in chrome too but not sure since when. And don't know about other. But investigating for such time I think it was solidated to be supported in all browser eventually
@Thaina reference types are still being worked on, but implementations are slowly catching up. The real problem is that the whole spec if very theoretical regarding improving interop. It's true, but wouldn't really change much in our context, only that the "reference type" would no longer be an integer like it is now.
Closing, implemented in master
and 3.4
. See this blog post
@Faless Are there any sample for C#
Describe the problem or limitation you are having in your project: Currently the only way to communicate with JavaScript code from Godot in HTML5 exports is by using
eval
, which, beside performing poorly, is also very limited.Describe the feature / enhancement and how it helps to overcome the problem or limitation: The idea is to expose an interface in the
JavaScript
singleton that allows to call JS functions and get JS properties in a Godot-y way.Ideally, the API should support almost all possible interactions with JavaScript, this include, getting/setting properties, calling functions, and handling callbacks and promises.
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: The idea is to expose a new
get_interface
method in theJavaScript
singleton, which will return aJavaScriptObject
.The "interface" will be registered via JavaScript (e.g. the custom HTML include):
You can create your own interface, or expose an external library (e.g. d3):
The interface will then be available to scripting via:
This is the proposed interface for
JavaScriptObject
:Conversion Table
This is the minimal types conversion table between Godot and JavaScript:
Some more specialized types (always copy for safety):
Promises & Callbacks
Passing callbacks to a function, or chaining asynchronous code, is a very common pattern in JavaScript, this is sadly not trivial to integrate with Godot due to scripts and application lifecycle. Following, is a proposed addition to the aforementioned API that would enable taking advantages of callbacks/promises but requiring a bit more consciousness during its usage. The idea is to add a method to the
JavaScript
singleton to bind a function reference:And 2 helper methods to the
JavaScriptObject
class:So you can interact with functions that requires callbacks this way:
And potentially, with promises this way:
This approach at promises could prove risky if we end up running the engine outside of the main thread in the future, due to the asynchronous nature of the calls, where a promise may throw an error or be rejected before a
catch
could be called. Due to this scenario, and the possibility that, in any case, a called function might throw an error and break the script, my suggestion is to always wrap the code in try/catch blocks and adding anerror
property toJavaScriptObject
that is!= OK
when the catch has been evaluated. This is still suboptimal, but the best I came up with.(Formalizes) Fixes: godotengine/godot-proposals#286 (Supersedes) Closes: godotengine/godot-proposals#1723