-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Loading and void script.evaluate() #796
Conversation
Thank you for adding all of the async examples! I think this will make coordinated testing on this issue much cleaner. That said: The issue (2) is not specifically that the loader never closes - it's that, as long as we're For example, try the following with this PR: <!-- Endless Loop with py-repl and py-onEvent -->
<body>
<style>
py-loader {
display:none
}
</style>
<py-repl>x = range(5)</py-repl>
<button id="b" py-onclick="import js; js.console.log("Logged!")></button>
<py-script>
import asyncio
for i in range(10):
print(f"A{i}")
await asyncio.sleep(1)
</py-script>
</body>
I don't believe we can directly await We also haven't fully solved the issue (1) of evaluation order here - I would propose an adjustment, based on your note in #751, to something you suggested: #runtime.ts
loader?.log('Initializing scripts...');
const scriptPromises = [];
for (const script of scriptsQueue_) {
scriptPromises.push( script.evaluate() );
}
- await Promise.all(scriptPromises);
+ void Promise.all(scriptPromises);
scriptsQueue.set([]); This allows the both the endless-loop-with-repl-and-button example above to function correctly, as well as the WebGL example (per #678) . All integration tests continue to pass. It does not solve the out-of-order-execution in |
Some whys... Why do we Why do we need to know it is done? Some scripts are never done. Why is At the root, the In this light, we should Also key is @JeffersGlass point that the downstream logic never is executed if we await and lifecycle is pretty important to get right. Let's ship |
Wow, cool work here! |
Yes. I think they would highlight various edge cases. |
I would like to get this into the |
Ok it looks like the change from: Breaks this example using Toga. http://localhost:8080/toga/freedom.html |
It feels like the regression in |
@tedpatrick Makes sense to me! I think these small breaks are worth it to maintain top-level-await not generally blocking initalization, and we can continue to dig deeper into the most correct behavior. For what it's worth, we've discussed moving the toga eaxmple to the Collective since it's based on a fairly heavily customized version of Toga, and uses some pre-built wheels of that customized version that rely other older behaviors in 2022.06.1. So I'm not entirely surprised that it's broken. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+0.5 to merge this PR.
I think that in general we need to take a step back and think about what are the async features we want to offer, the patterns we want to support and the subtle interactions between the JS and Python event loops.
But this PR partially solves some of the problems so it's surely a step forward.
That said, it definitely lacks tests.
I am with @marimeireles here: instead of having example/await*.html
, we should have test/integration/test_await.py
which contains all the relevant cases we want to test. E.g.:
def test_multiple_async(self):
self.pyscript_run(
"""
<py-script>
import js
import asyncio
for i in range(3):
js.console.log('A', i)
await asyncio.sleep(0.1)
</py-script>
<py-script>
import js
import asyncio
for i in range(3):
js.console.log('B', i)
await asyncio.sleep(0.1)
</py-script>
"""
)
assert self.console.log.lines == [
'A 0',
'B 0',
'A 1',
'B 1',
'A 2',
'B 2'
]
Given the timeframe to getting |
LGTM! Is it worth adding a comment/tag to the examples of what their expected output should be, or what it is as of this PR? We have the context captured here and in #751 , but wondering if that would be useful direclty within the |
for more information, see https://pre-commit.ci
Added a test. Also discovered the benefits of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you!
Once this builds. I am deploying as snapshot as |
This PR is intended to fix #751
I believe we have 2 conflicting issues.
I believe we need to await all calls to
script.evaluate()
but I believe we need to do this within a Promise.all like so:This results in very accurate loading behavior on all but 2 examples: Endless loop and root async await. These 2 examples are related 100% to the loader closing but there is nothing wrong with them logically. This example was provided by @JeffersGlass
The other example is the webgl/raycaster. Both work perfectly with py-loader set to
display:none
The py-loader can be easily hidden as follows using CSS.
This is not ideal either but downstream we can make the loader event aware so endless loops or root await that never return can be handled with an API.
I want to support the endless looping use case but we are not yet ready with a programmatic loader for these cases. Ideally, we can get this into the 2022.10.1 release, and better support these use cases.