Skip to content

Merge CE setImmediate docs into README #28

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 5 commits into from
Nov 9, 2021

Conversation

armanbilge
Copy link
Member

Tried to keep the best of both explanations, while adjusting for the wider audience here!

README.md Outdated
}, 0);
```

Each timeout sets a new timeout, and so on and so on. This is exactly the sort of situation that we get into when chaining `Future`s, where each `map`/`flatMap`/`transform`/etc. schedules a another `Future` which, in turn will schedule another... etc. etc. This is exactly where we see clamping. In particular, the innermost `setTimeout` in this example will be clamped to 4 milliseconds (meaning there is no difference between `setTimeout(.., 0)` and `setTimeout(.., 4)`), which would slow down execution *even more*.
Copy link
Member Author

Choose a reason for hiding this comment

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

Did I explain this right, in terms of Future?

README.md Outdated
@@ -44,16 +44,66 @@ loop()

The `loop()` future will run forever when using the default Scala.js executor, which is written in terms of JavaScript's `Promise`. The *reason* this will run forever stems from the fact that JavaScript includes two separate work queues: the [microtask and the macrotask queue](https://javascript.info/event-loop). The microtask queue is used exclusively by `Promise`, while the macrotask queue is used by everything else, including UI rendering, `setTimeout`, and I/O such as Fetch or Node.js things. The semantics are such that, whenever the microtask queue has work, it takes full precedence over the macrotask queue until the microtask queue is completely exhausted.

This explains why the above snippet will run forever on a `Promise`-based executor: the microtask queue is *never* empty because we're constantly adding new tasks! Thus, `setTimeout` is never able to run because the macrotask queue never receives control.
This explains why the above snippet will run forever on a `Promise`-based executor: the microtask queue is *never* empty because we're constantly adding new tasks! Thus, `setTimeout` is never able to run because the macrotask queue never receives control. This is horrible, even by JavaScript standards.
Copy link
Member

Choose a reason for hiding this comment

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

Could we avoid being condescending at JavaScript, please? Scala.js doesn't make that kind of judgment calls. I don't think this new sentence brings any positive value.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm sorry, I knew better but I shoe-horned this in anyway. Besides adjusting for the new audience I forgot to adjust for the new venue.

I suppose line 81 below should be dropped/reworked too? Anything else?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, perhaps remove "an all-too familiar patchwork of" from line 81. The sentence should otherwise stand on its own.

Other than that I think it's fine.

README.md Outdated

Fortunately, we aren't the only ones to have this problem. What we *want* is something which uses the macrotask queue (so we play nicely with `setTimeout`, I/O, and other macrotasks), but which doesn't have as much overhead as `setTimeout`. The answer is `setImmediate`.

The `setImmediate` function was first introduced in NodeJS, and its purpose is to solve *exactly* this problem: a faster `setTimeout(..., 0)`. In particular, `setImmediate(...)` is *semantically* equivalent to `setTimeout(0, ...)`, except without the associated clamping: it doesn't include a delay mechanism of any sort, it simply takes a callback and immediately submits it to the event loop, which in turn will run the callback as soon as its turn comes up.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
The `setImmediate` function was first introduced in NodeJS, and its purpose is to solve *exactly* this problem: a faster `setTimeout(..., 0)`. In particular, `setImmediate(...)` is *semantically* equivalent to `setTimeout(0, ...)`, except without the associated clamping: it doesn't include a delay mechanism of any sort, it simply takes a callback and immediately submits it to the event loop, which in turn will run the callback as soon as its turn comes up.
The `setImmediate` function was first introduced in Node.js, and its purpose is to solve *exactly* this problem: a faster `setTimeout(..., 0)`. In particular, `setImmediate(...)` is *semantically* equivalent to `setTimeout(0, ...)`, except without the associated clamping: it doesn't include a delay mechanism of any sort, it simply takes a callback and immediately submits it to the event loop, which in turn will run the callback as soon as its turn comes up.

There are more of those in the page.

README.md Outdated

That's the bad news. The good news is that all modern browsers include *some* sort of functionality which can be exploited to emulate `setImmediate` with similar performance characteristics. In particular, *most* environments take advantage of `postMessage` in some way. If you're interested in the nitty-gritty details of how this works, you are referred to [this excellent readme](https://github.com/YuzuJS/setImmediate#the-tricks).

scala-js-macrotask-executor implements *most* of the `setImmediate` polyfill in terms of ScalaJS, wrapped up in an `ExecutionContext` interface. The only elements of the polyfill which are *not* implemented are as follows:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
scala-js-macrotask-executor implements *most* of the `setImmediate` polyfill in terms of ScalaJS, wrapped up in an `ExecutionContext` interface. The only elements of the polyfill which are *not* implemented are as follows:
scala-js-macrotask-executor implements *most* of the `setImmediate` polyfill in terms of Scala.js, wrapped up in an `ExecutionContext` interface. The only elements of the polyfill which are *not* implemented are as follows:

There are more of those in the page.

README.md Outdated
@@ -13,7 +13,7 @@ libraryDependencies += "org.scala-js" %%% "scala-js-macrotask-executor" % "1.0.0
Published for Scala 2.11, 2.12, 2.13, 3. Functionality is fully supported on all platforms supported by Scala.js (including web workers). In the event that a given platform does *not* have the necessary functionality to implement `setImmediate`-style yielding (usually `postMessage` is what is required), the implementation will transparently fall back to using `setTimeout`, which will drastically inhibit performance but remain otherwise functional.

```scala
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._
import org.Scala.js.macrotaskexecutor.MacrotaskExecutor.Implicits._
Copy link
Member

Choose a reason for hiding this comment

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

Search-and-replace artifact ;)

Copy link
Member Author

Choose a reason for hiding this comment

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

😳 seems I leaked some of my internal implementation details 😉

Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
import org.Scala.js.macrotaskexecutor.MacrotaskExecutor.Implicits._
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._

Co-authored-by: Sébastien Doeraene <sjrdoeraene@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants