To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CAKQgqTY4QNQA45WgAyFJba1jd2aAWyakHOKYs02Vy48rmG8Atw%40mail.gmail.com.
... (if there are no other awaits in this fn) the caller can't be sure whether the code will return synchronously or not. For a while our linting rules forbade non-top-level awaits for this reason. After pushback and discussion, other voices convinced us all that the correct rule is that a non-top-level await (i.e. await in a loop or conditional) can't be the first await in a function, and that's what we enforce now.
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CAKQgqTZiPFw7M18sS6-gZp2Rmq4SWSENX9VPe-PwyQSj-MGUVg%40mail.gmail.com.
MarkM has convinced us at Agoric that this form is usually a bad idea:
let result;
if (condition) {
result = await foo();
} else {
result = "";
}
(if there are no other awaits in this fn) the caller can't be sure
whether the code will return synchronously or not. For a while our
linting rules forbade non-top-level awaits for this reason. After
pushback and discussion, other voices convinced us all that the correct
rule is that a non-top-level await (i.e. await in a loop or conditional)
can't be the first await in a function, and that's what we enforce now.
This means that if you can't come up with a better alternative, you can
precede the above with `await null;` and pass the linter. The effect is
that callers will always get a promise from this function.
I found the rest of the doc's focus on controlling the order in which
events occur to be jarring. I'll admit that I don't write much UI code,
but one of the things I've learned from writing in JavaScript is to
accept that async functions will return results "later". I write a lot
of .then() clauses (though we have a different syntax for them) and
expect things to be taken care of eventually. This can make testing
difficult, but in a distributed system, you can't expect local immediate
actions. In tests, I often make mocks that allow me to control the
timing of responses.
We've recently added tools that provide for durable handling of
promises, which means it's possible to write long-lived services that
rely on other long-lived services, and expect to survive a restart or
upgrade of either the code you're writing or code you're depending on.
It's quite powerful.
Chris
--
The government's efforts to expand "access" to care while limiting
costs are like blowing up a balloon while simultaneously squeezing
it. The balloon continues to inflate, but in misshapen form.
---David Goldhill
Chris Hibbert
hib...@mydruthers.com
Blog: http://www.pancrit.org
http://mydruthers.com
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/85a5bf47-27cd-45c9-b33c-bccb1dd368ee%40mydruthers.com.
On Mar 8, 2024, at 1:40 PM, Alan Karp <alan...@gmail.com> wrote:On Fri, Mar 8, 2024 at 8:53 AM Chris Hibbert <hib...@mydruthers.com> wrote:
MarkM has convinced us at Agoric that this form is usually a bad idea:
let result;
if (condition) {
result = await foo();
} else {
result = "";
}
(if there are no other awaits in this fn) the caller can't be sure
whether the code will return synchronously or not. For a while our
linting rules forbade non-top-level awaits for this reason. After
pushback and discussion, other voices convinced us all that the correct
rule is that a non-top-level await (i.e. await in a loop or conditional)
can't be the first await in a function, and that's what we enforce now.Not a bad policy, but the fact that you need it reflects poorly on the tooling. I can't await foo unless foo returns a promise, so I shouldn't be able to ignore the return value of an async function. If that violates the spirit of JavaScript, the IDE should at least warn you. VSCode does not.
This means that if you can't come up with a better alternative, you can
precede the above with `await null;` and pass the linter. The effect is
that callers will always get a promise from this function.
Inserting something like `await null;` will force any code that follows it into a separate turn unconditionally and thereby spare you the pain.
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/59C79995-74DE-4B87-8A93-0DA37C9B2C18%40fudco.com.
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/59C79995-74DE-4B87-8A93-0DA37C9B2C18%40fudco.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CANpA1Z2wDkfkC8c5V-q0mTfVnDrXiLNN1aGXBHtW%2BLkKt%2BkXnw%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CAKQgqTZAO9KcjaXeX3fVYTCdMPa%3DZg6q9cwN_UuL60tnQBu_PQ%40mail.gmail.com.
On Fri, Mar 8, 2024 at 3:04 PM Chip Morningstar <ch...@fudco.com> wrote:
>
> As I understand it, the issue is that if you have two (or more) execution paths, one of> which passes through an `await` and the other of which does not, then you can have> code inside the function that might or might not execute within the same turn as the> caller depending on conditions.>
While that's certainly true when using .then, is it true with await?
Consider
if (condition) {
result = ... // 1
} else {
asyncfn().then((result) => {
... // 2
});
}
... // 3
In this case, the order is 1, 3 in the same microturn if the condition is true and 3, 2 in different microturns if it is false. The hazard Chip points out can occur. (I believe that's why I was seeing some odd behavior before changing to the next pattern.)
The way to avoid that problem is to create a continuation.
if (condition) {
result = ... // 1
remainder(result)
} else {
asyncfn().then((result) => {
... // 2
remainder(result)
});
}
function remainder(result) {
... // 3
}
The order is then 1,3 in the same microturn for true and 2, 3 in the same microturn for false, which avoids the hazard.
An alternative is
if (condition) {
result = ... // 1
} else {
result = await asyncfn();
... // 2
}
... // 3
I believe the sequence is 1, 3 in the same microturn if the condition is true and 2, 3 in the same microturn if it is false. The hazard Chip points out cannot occur.
Did I get that right?
--------------
Alan Karp
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CANpA1Z0WrnSkEkfaV0j0JZ%2BEw9PmTmK%2BvONgK0nj8F-cL7uhEw%40mail.gmail.com.
There's no such thing as a "microturn". You mean "turn".
An alternative is
if (condition) {
result = ... // 1
} else {
result = await asyncfn();
... // 2
}
... // 3
I believe the sequence is 1, 3 in the same microturn if the condition is true and 2, 3 in the same microturn if it is false. The hazard Chip points out cannot occur.
Did I get that right?No. Put a "// 0" before the if. Now 0 and 3 are either in the same of different turns depending on condition.// 0if (condition) {
result = ... // 1
} else {
result = await asyncfn();
... // 2
}
... // 3
On Tue, Mar 12, 2024 at 10:23 AM Mark S. Miller <eri...@gmail.com> wrote:There's no such thing as a "microturn". You mean "turn".I'm thinking of the behavior of paste. The body of a setTimeout runs after the DOM update. That's clearly the next turn. The body of a promise runs before the DOM update but after other code. I made up the word "microturn" to make that distinction.
An alternative is
if (condition) {
result = ... // 1
} else {
result = await asyncfn();
... // 2
}
... // 3
I believe the sequence is 1, 3 in the same microturn if the condition is true and 2, 3 in the same microturn if it is false. The hazard Chip points out cannot occur.
Did I get that right?No. Put a "// 0" before the if. Now 0 and 3 are either in the same of different turns depending on condition.// 0if (condition) {
result = ... // 1
} else {
result = await asyncfn();
... // 2
}
... // 3True, but does that exhibit the hazard that Chip pointed out? Does it create any other hazards? The answer would be yes if the behavior was like setTimeout because the two cases might see different DOM states. Of course, the safe thing to do is to add an "await null" to the other branch, so I'm just asking out of general interest..
--
--------------
Alan Karp
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CANpA1Z3yzvPhJe6nQthURF%3DZ8GJTZgHhEEfd-%2B7hu6Jy0W7o6g%40mail.gmail.com.
On Tue, Mar 12, 2024 at 11:27 AM Alan Karp <alan...@gmail.com> wrote:On Tue, Mar 12, 2024 at 10:23 AM Mark S. Miller <eri...@gmail.com> wrote:There's no such thing as a "microturn". You mean "turn".I'm thinking of the behavior of paste. The body of a setTimeout runs after the DOM update. That's clearly the next turn. The body of a promise runs before the DOM update but after other code. I made up the word "microturn" to make that distinction.No, the unit of servicing the low priority queue is not a turn, by definition. A turn is the interval between an empty stack and an empty stack in an event-loop system. This can only be the unit of servicing the highest priority queue.What you're referring to is a browser concept, not an event-loop concept. Browser terminology doesn't use the term "turn" anyway.
Alan, here's a more apt definition of "microturn": turns contain
microturns. The turn pops an event off of the event queue and invokes
the event handler, which takes the first microturn. The event handler
may queue microtasks in the microtask queue and events in the event
queue. When the event handler is done, the execution stack is empty,
but microtasks remain in the microtask queue. Handling a microtask
takes a microturn, in this terminology. Once the microtask queue is
empty, the turn ends and the browser moves on to the next event in the
event queue.
> If the whole thing is preceded by an "await null;" outside the condition at top level, then 3 always happens in a separate turn after the caller has completed.
In this terminology, preceding by "await null;" means 3 always happens
in a future microturn after the caller has completed, but it will
happen in the same turn if the condition flag is set and a different
turn otherwise.
To make sure that 3 always happens in another turn, use
await new Promise((resolve)=>setTimeout(resolve,0));
On Tue, Mar 12, 2024 at 12:37 PM Mark S. Miller <eri...@gmail.com> wrote:
> On Tue, Mar 12, 2024 at 11:27 AM Alan Karp <alan...@gmail.com> wrote:
>> On Tue, Mar 12, 2024 at 10:23 AM Mark S. Miller <eri...@gmail.com> wrote:
>>>
>>> There's no such thing as a "microturn". You mean "turn".
>>
>> I'm thinking of the behavior of paste. The body of a setTimeout runs after the DOM update. That's clearly the next turn. The body of a promise runs before the DOM update but after other code. I made up the word "microturn" to make that distinction.
>
> No, the unit of servicing the low priority queue is not a turn, by definition. A turn is the interval between an empty stack and an empty stack in an event-loop system. This can only be the unit of servicing the highest priority queue.
Alan, here's a more apt definition of "microturn": turns contain
microturns. The turn pops an event off of the event queue and invokes
the event handler, which takes the first microturn. The event handler
may queue microtasks in the microtask queue and events in the event
queue. When the event handler is done, the execution stack is empty,
but microtasks remain in the microtask queue. Handling a microtask
takes a microturn, in this terminology. Once the microtask queue is
empty, the turn ends and the browser moves on to the next event in the
event queue.
> if (condition) {
> result = ... // 1
> } else {
> result = await asyncfn();
> ... // 2
> }
> ... // 3
Here if the condition flag is set, 1 and 3 happen in the first
microturn, the event handler. If the condition flag is unset and
asyncfn only uses promises, then 3 happens in the first microturn and
2 happens in a later microturn, but both are handled in the same turn.
If the condition flag is not set and asyncfn uses something like
setTimeout or fetch that wait on an event, 3 happens in the first
microturn and the turn ends, then 1 happens in a future turn.
> If the whole thing is preceded by an "await null;" outside the condition at top level, then 3 always happens in a separate turn after the caller has completed.
In this terminology, preceding by "await null;" means 3 always happens
in a future microturn after the caller has completed, but it will
happen in the same turn if the condition flag is set and a different
turn otherwise.
To make sure that 3 always happens in another turn, use
await new Promise((resolve)=>setTimeout(resolve,0));
--
Mike Stay - meta...@gmail.com
https://math.ucr.edu/~mike
https://reperiendi.wordpress.com
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CAKQgqTYimGKe_t3%3DN2H1D_esRHBzffb3nm%2BQ1a7NedkBa%2BtEgQ%40mail.gmail.com.
----------------
Alan Karp
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CANpA1Z3OvtF6PTwBwUDwh25nkYwHd3EL1xq50x1QuSHqpsBHJQ%40mail.gmail.com.
--
You received this message because you are subscribed to the Google Groups "friam" group.
To unsubscribe from this group and stop receiving emails from it, send an email to friam+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/friam/CAKQgqTZfWnSk-bPPk%3DA%3D5fpz4q%3DD0wtJy-knw8Aac1j5f_it1Q%40mail.gmail.com.