8000 Improved py:all-done event by WebReflection · Pull Request #1778 · pyscript/pyscript · GitHub
[go: up one dir, main page]

Skip to content

Improved py:all-done event #1778

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

Merged
merged 1 commit into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Improved py:all-done event
  • Loading branch information
WebReflection committed Oct 2, 2023
commit 233eb758cd549b0eefa2e1236768efa1c7abce42
8 changes: 4 additions & 4 deletions pyscript.core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyscript.core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"polyscript": "^0.4.8",
"polyscript": "^0.4.11",
"type-checked-collections": "^0.1.7"
},
"devDependencies": {
Expand Down
61 changes: 8 additions & 53 deletions pyscript.core/src/all-done.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,17 @@
import TYPES from "./types.js";
import hooks from "./hooks.js";

const DONE = "py:all-done";

const {
onAfterRun,
onAfterRunAsync,
codeAfterRunWorker,
codeAfterRunWorkerAsync,
} = hooks;

const waitForIt = [];
const codes = [];

const codeFor = (element) => {
const isAsync = element.hasAttribute("async");
const { promise, resolve } = Promise.withResolvers();
const type = `${DONE}:${waitForIt.push(promise)}`;

// resolve each promise once notified
addEventListener(type, resolve, { once: true });

if (element.hasAttribute("worker")) {
const code = `
from pyscript import window as _w
_w.dispatchEvent(_w.Event.new("${type}"))
`;
if (isAsync) codeAfterRunWorkerAsync.add(code);
else codeAfterRunWorker.add(code);
return code;
for (const [TYPE] of TYPES) {
const selectors = [`script[type="${TYPE}"]`, `${TYPE}-script`];
for (const element of document.querySelectorAll(selectors.join(","))) {
const { promise, resolve } = Promise.withResolvers();
waitForIt.push(promise);
element.addEventListener(`${TYPE}:done`, resolve, { once: true });
}

// dispatch only once the ready element is the same
const code = (_, el) => {
if (el === element) dispatchEvent(new Event(type));
};

if (isAsync) onAfterRunAsync.add(code);
else onAfterRun.add(code);
return code;
};

const selector = [];
for (const [TYPE] of TYPES)
selector.push(`script[type="${TYPE}"]`, `${TYPE}-script`);

// loop over all known scripts and elements
for (const element of document.querySelectorAll(selector.join(",")))
codes.push(codeFor(element));
}

// wait for all the things then cleanup
Promise.all(waitForIt).then(() => {
// cleanup unnecessary hooks
for (const code of codes) {
onAfterRun.delete(code);
onAfterRunAsync.delete(code);
codeAfterRunWorker.delete(code);
codeAfterRunWorkerAsync.delete(code);
}
dispatchEvent(new Event(DONE));
dispatchEvent(new Event("py:all-done"));
});
26 changes: 19 additions & 7 deletions pyscript.core/src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ const exportedConfig = {};
export { exportedConfig as config, hooks };

for (const [TYPE, interpreter] of TYPES) {
const dispatchDone = (element, isAsync, result) => {
if (isAsync) result.then(() => dispatch(element, TYPE, "done"));
else dispatch(element, TYPE, "done");
};

const { config, plugins, error } = configs.get(TYPE);

// create a unique identifier when/if needed
Expand Down Expand Up @@ -211,9 +216,13 @@ for (const [TYPE, interpreter] of TYPES) {
defineProperty(element, "target", { value: show });

// notify before the code runs
dispatch(element, TYPE);
wrap[`run${isAsync ? "Async" : ""}`](
await fetchSource(element, wrap.io, true),
dispatch(element, TYPE, "ready");
dispatchDone(
element,
isAsync,
wrap[`run${isAsync ? "Async" : ""}`](
await fetchSource(element, wrap.io, true),
),
);
} else {
// resolve PyScriptElement to allow connectedCallback
Expand Down Expand Up @@ -246,18 +255,21 @@ for (const [TYPE, interpreter] of TYPES) {
async connectedCallback() {
if (!this.executed) {
this.executed = true;
const isAsync = this.hasAttribute("async");
const { io, run, runAsync } = await this._wrap.promise;
const runner = this.hasAttribute("async") ? runAsync : run;
this.srcCode = await fetchSource(
this,
io,
!this.childElementCount,
);
this.replaceChildren();
// notify before the code runs
dispatch(this, TYPE);
runner(this.srcCode);
this.style.display = "block";
dispatch(this, TYPE, "ready");
dispatchDone(
this,
isAsync,
(isAsync ? runAsync : run)(this.srcCode),
);
}
}
}
Expand Down
30 changes: 30 additions & 0 deletions pyscript.core/test/display.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PyScript Next</title>
<script>
addEventListener("py:all-done", ({ type }) => console.log(type));
</script>
<link rel="stylesheet" href="../dist/core.css">
<script type="module" src="../dist/core.js"></script>
</head>
<body>
<script type="py" worker async>
from pyscript import display
display('hello 1')

import js
import time
js.console.log('sleeping...')
time.sleep(2)
js.console.log('...done')
</script>
<p>hello 2</p>
<script type="py" worker async>
from pyscript import display
display('hello 3')
</script>
</body>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should become a proper integration test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could do a follow up but the feature is from polyscript so eventually tests should be done there, imho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, never mind, these probably should be done in both places because custom types events are not polyscript matter anymore ... that being said, we currently have time working in either sync or async scripts/elements ... not sure how to test this best as async and time don't really use async feature there. If you'd like to add a better test, please go ahead, thank you!

</html>
0