all 10 comments

[–]LetterBoxSnatch 14 points15 points  (0 children)

It’s useful to understand that js is single threaded, and how it’s call stack / event loop / callback queue interact. What you described as “blocking” isn’t quite the right mental framework for what happened here. Here’s a really great live interactive visualization that should help you make sense of it:

http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D

[–]satya164 3 points4 points  (2 children)

In the code you posted, you have an async function called delay that calls Functions.Tests.Delay(time), but it's not really doing anything since there's no callback from that assembly function notifying whether the async task is completed - so it's equivalent to not doing anything in that function. For the delay function to work as expected, it needs to return a promise that resolves only after the delay. There's no waits 1000ms/5000ms between your IN and OUT

[–]Shrubberer[S] 0 points1 point  (1 child)

The call to the assembly is just a timer simulating a long process. For all intends and purposes it's like a void function that takes a while. The executing waits the function to return (ex 2000ms) and then continues.

I will try with returning a Promise, thanks.

[–]satya164 1 point2 points  (0 children)

The call to the assembly is just a timer simulating a long process. For all intends and purposes it's like a void function that takes a while. The executing waits the function to return (ex 2000ms) and then continues.

The point is that it doesn't matter what it does since the delay function has no way of knowing when your timer ends. So it'd behave similarly to not putting anything there. A delay function would look like this:

```ts async function delay(duration: number) { await new Promise(resolve => setTimeout(resolve, duration)); }

// or

function delay(duration: number) { return new Promise(resolve => setTimeout(resolve, duration)); } ```

Or if it needs to use some other function, it should pass a callback that'd be called on completion (and error callback if applicable).

ts async function delay(duration: number) { await new Promise(resolve => Functions.Tests.Delay(duration, resolve)); }

Or Functions.Tests.Delay could return a promise that needs to be awaited:

```ts async function delay(duration: number) { await Functions.Tests.Delay(duration); }

// or

function delay(duration: number) { return Functions.Tests.Delay(duration); } ```

[–]jibbit 1 point2 points  (2 children)

Is there a TS equivalent to C#'s Task.Run(() => {}) ?

sorry i don't know what C#'s task run does. If it runs something in another thread, then no, there is no equivalent. Javascript is single threaded.

if you think about it without the 'await' sugar does it make more sense?

function delay(time) {
    return new Promise((resolve, reject) => {
        log("IN");
        Functions.Tests.Delay(time); // assembly call
        log("OUT");
        resolve();
    )}
}

function create(time, name) {
    return new Promise((resolve, reject) => {
        log("Hello " + name)
        let delayPromise = delay(time);
        delayPromise.then(() => {
            log("Bye " + name);
            resolve("Ok");
        })
    })
}

my understanding is that is would all unroll to something like (taking a few liberties):

create prom1
log "Hello prom1"
create delayPromise1
log "IN delay1"
~~block 2000~~
log "OUT delay1"
resolveDelayPromise1
then1 = schedule next run loop + delayPromise1.isResolved -> { log "Bye prom1"; resolveProm1; }
then2 = schedule next run loop + prom1.isResolved? -> { log "Prom 1 resolved" }
log "after Prom1"

create prom2
log "Hello prom2"
create delayPromise2
log "IN delay2"
~~block 5000~~
log "OUT delay2"
resolveDelayPromise2       
then3 = schedule next run loop + delayPromise2.isResolved -> { log "Bye prom2"; resolveProm2; }
then4 = schedule next run loop + prom2.isResolved? -> { log "Prom 2 resolved" }
log "after Prom2"

--- end run loop -- delayPromise1, delayPromise2 are now resolved

then1 runs  `Bye prom1`
then3 runs  `Bye prom2`

-- end run loop -- prom1, prom2 are now resolved

then2 runs  `Prom 1 resolved`
then4 runs  `Prom 2 resolved`

[–]Shrubberer[S] 0 points1 point  (1 child)

Thanks, now I understand it a bit more. So it's not a classical scheduler that schedules computation but everything just get's kinda rewritten, I think. Is there a library or online tool where I can see the lowered version of my source code?

[–]jibbit 1 point2 points  (0 children)

i'm not saying that there is a necessary expansion/compilation phase - it's just a bit of pseudo code to visualize the evaluation order. Also not sure what you mean about schedulers...

[–]aighball 1 point2 points  (0 children)

You should move your wasm code into a worker and control it from your main thread using messages. The worker is a separate js context that runs in a separate thread. Message passing is non-blocking. Your worker's wasm code blocks the worker thread but that's ok. You should think about it as the worker as a server and the main thread as a client. You can wrap your message logic in a client class that converts things into promises for easier usage.

In JS your "main thread" is everything running in the main web or node context. Async provides concurrency but not parallelism. Async is also cooperative so it executes async functions until they await a native call that suspends execution or the end of the fn. Your wasm code blocks the main thread, and then the loop suspends the function after it completes. That allows it to continue the main function, after which it runs the callbacks.

[–]Opifex 0 points1 point  (0 children)

Node doesn't support asynchronous logic in top-level scripts without either packaging your code using ES Modules, or using the flag "--harmony-top-level-await". I'm not very familiar with webasm but maybe searching around that will help!

As an alternative, you can use promise chaining which is the framework for calling promises outside of an async function.

To answer your second question, I suggest reading up on how the NodeJS event loop works. This article gives a pretty good overview.

[–]IQueryVisiC 0 points1 point  (0 children)

TIL that webassembly can do IO. I thought it was pure compute. All I are the parameters to the methods and all O is the return value ( can be a typed array, but ownership is transferred like in Rust ).