Live data from Hacker News

V8 adds support for top-level await

chromium.googlesource.com

211–220 of 310 posts

Re: V8 adds support for top-level await

#211
post #48

All this async code without decent locking primitives is leading to a rabbit hole of race conditions... It doesn't matter that it's all single threaded if all your function calls may or may not block and run a bunch of other code in the meantime, mutating all kinds of state. I feel like JavaScript developers of the 2020's are going to relearn the same things the C programmers of the 1990's learn, just a few levels of…

Data races are impossible in JavaScript because it's single-threaded. Race conditions are possible in any language that can do anything asynchronous, which is basically all of them. But the general benefit you get from JS being single-threaded is the fact that any given callback is transactional. No other code will ever come in and mutate state between two regular lines of JavaScript code. Achieving this is pretty mu…

Ehh, I get where you're coming from, but await is at least explicit about it. Did you promise.then()? Did you call this function by putting an await in front of it? You yielded on purpose. If you need to keep hold of a resource on either side of that explicit action, either don't use either of those constructs, do but write a locking mechanism, or stop and think long and hard about why the lock is necessary.

Granted, my practical experience is limited. I haven't really run into any of these kinds of situations outside of database work in Node, and there you've got the major benefit of transactions to do the locking for you, so the async JavaScript code doesn't have to particularly care and can yield whenever it wants.

For me, the real benefit of await / async so far has mostly just been about improving code flow. Promises were already an excellent solution to the async problem, but their syntax for all but the most trivial example is something only a mother could love. async/await makes the code structure suddenly not necessarily look like callback hell, and in a lot of cases it's much more compact and easier to read. It greatly improves the chances that when I come back to it a month later, I won't have to reach back into the past and slap myself for writing that monstrosity. :)

Re: V8 adds support for top-level await

#212

Earlier quoted context omitted.

> It doesn't matter that it's all single threaded if all your function calls may or may not block and run a bunch of other code in the meantime, mutating all kinds of state. Can you elaborate a bit more on this? I'm unsure about how locking in a single-threaded environment would work. And how would it really differ from async/await or promises which can handle race conditions already? One area where the lack-of locki…

In javascript anywhere you see await, you've introduced an explicit scheduling point. There are cases where even in a single threaded env you want to "wait" until some other async process is complete. To use one of the old school examples: function transfer(amount, acct1, acct2) { var current_balance = await acc1.balance() if current_balance > amount { await acct1.sub(amount) await acct2.add(amount) } } Now what happ…

You'd need to lock both accounts... but even then. Doing any kind of accounting operations without being atomic, transactional or idempotent is just wrong. Even with single call - acct2.add() could fail and you're left with broken state. If this is in-memory state then you don't need asyncs at all. If it's not, Locks just give you false sense of safety.

Re: V8 adds support for top-level await

#213

All this async code without decent locking primitives is leading to a rabbit hole of race conditions... It doesn't matter that it's all single threaded if all your function calls may or may not block and run a bunch of other code in the meantime, mutating all kinds of state. I feel like JavaScript developers of the 2020's are going to relearn the same things the C programmers of the 1990's learn, just a few levels of…

Javascript devs, for all their flaws, understand async programming far, far better than the average C programmer. Indeed, your assertion that we need "locking primitives" to counteract "race conditions" is evidence of that. Yes, JavaScript can have race conditions, but not multi-threaded race conditions that cause resource contention [0]. So what good would locking primitives be? And as a solution to single-threaded…

The most common need I've found for some kind of locking mechanism in JavaScript is the very basic example of asynchronous functions triggered by UI. For example, button -> http call -> navigate. If the user presses the button twice, the call is made twice before navigating, which has unexpected results in some cases.

The lock in this case could be as simple as disabling the button as soon as the user clicks on it, but I've also find Promise-based locking functions to be very useful in solving these kind of problems.

I wouldn't call these "primitives" though - you don't need a language construct for it. It's easy enough to build the locks as functions working with Promises.

Re: V8 adds support for top-level await

#214
post #29

Earlier quoted context omitted.

I think JS devs usually use async/await for network calls and not really for computation or file access. Those type of applications are better served by other languages. A deadlock in the problem space that JavaScript operates in would be a rarity I feel.

JS is single-threaded right so (...I think...) deadlocks are actually impossible. Although I guess you can still get stuck if two pieces of code are waiting on each other to satisfy some condition (and trading control of the sole thread) without using explicit locking.

Deadlocks can happen in any kind of concurrent system with locks. As soon as you start building & using locks with Promises, this is quite easy to happen.

That said, the need for locks in JavaScript is much less than in a typical multi-threaded language, so it's a lot easier to keep track of and avoid deadlocks, if you're even using locks at all.

Re: V8 adds support for top-level await

#216

All this async code without decent locking primitives is leading to a rabbit hole of race conditions... It doesn't matter that it's all single threaded if all your function calls may or may not block and run a bunch of other code in the meantime, mutating all kinds of state. I feel like JavaScript developers of the 2020's are going to relearn the same things the C programmers of the 1990's learn, just a few levels of…

> All this async code without decent locking primitives is leading to a rabbit hole of race conditions...

That was an issue long before async/await was a thing.

Re: V8 adds support for top-level await

#217
post #70

Earlier quoted context omitted.

One use case I often find is a caching layer between JS and a HTTP call. If there are 2 calls to a non cached endpoint, the HTTP will fire off twice before caching the result. You can work around this by returning the first promise from the cache, but this is essentially a mutex. Having locking primitives would solve this and require less boilerplate code.

You write this boilerplate to avoid one extra non-cached HTTP call on a (browser?) client? Am I understanding correctly?

One extra call could be a multi-megabyte video chunk, or the code flow might mean this case always occurs, potentially hundreds of times before the promise resolves.

Re: V8 adds support for top-level await

#218
post #132
post #114

Earlier quoted context omitted.

You're reading too much into the example. Your 'database' can be your frontend js state. There is nothing in the example that limits the problem to backend development.

Yeah but the impact of race conditions on front-end code (which is always single user) is minimal; unlike the backend where it's catastrophic and not fixable by refreshing the page.

It is fixable by refreshing the page if there are no race conditions in the front-end.

If anything getting this right on the front-end is often extra problematic because of the high cost of round-tripping state to the server.

Re: V8 adds support for top-level await

#219
post #114

Earlier quoted context omitted.

You're reading too much into the example. Your 'database' can be your frontend js state. There is nothing in the example that limits the problem to backend development.

In that case, the code would be sync and there wouldn't be a "race condition".

I just the other day had to step in to deal with a race condition in a frontend caused by improperly handling async API requests.

It's dangerous to assume that just because JS has a single main thread that you don't need to think about sequencing of operations and locking.

Re: V8 adds support for top-level await

#220

Earlier quoted context omitted.

Maybe he meant why not const?

Const is a complete waste of time for non-primitive types. I defy anyone to show me a single bug in a popular program that could have been prevented by using const for a function local object. It can’t be done. There are bugs caused by mutatable state. There are bugs caused by reassigning globals. There has never been a bug caused by reassigning a function local variable while leaving it mutable.

The const keyword has absolutely nothing to do with state mutability, that is a misconception. const in es6 is a keyword meant to explicitly prohibit identifier reassignment and it does indeed reduce bugs because it communicates developer intention regarding how a variable reference is expected to behave in a section of code. Further, use of const by default is a best practice because it leaves less room for error in cases where a reassignment must never occur and increases readability by convention of the let keyword signaling that a reference will behave in a volatile way in proximal logic.
Post reply on HN