(They want to do that because alert() "stops the world" by blocking the main thread event loop, and because they make it easy for a site to post a message that appears to come from Chrome itself, or from another website.)
https://groups.google.com/a/chromium.org/g/blink-dev/c/hTOXi...
> We’re on a long, slow path to deprecate and remove window.alert/confirm/prompt and beforeunload handlers due to their role in user-hostile event loop pausing, as well as phishing and other abuse mechanisms. We’ve been successfully chipping away at them in various cases, e.g. background tabs, subframes with no user interaction, and now cross-origin subframes. Each step is hard-fought progress toward the eventual goal, and we should consider carefully whether we want to regress, even in an opt-in manner.
Rich Harris has a good blog post about this. https://dev.to/richharris/stay-alert-d
But on the serious side, this is useful for many antiquated apps (e.g. government stuff) that break tons of stuff if you attempt to re-submit a form, use the back button, etc, so I see that causing a ton of problems.
I still haven’t found a way to consistently send a request while the tab/browser is closing.
Why would you need it to be consistent? Depending on this for anything other than analytics is bad design. It’s like catching sigterm on desktop.
Ok, alert is ugly, but for a lot of situations (= industrial software) it's perfectly acceptable.
alert('whatever');
This cannot: const answer = confirm('A querstion?');
const value = doSomethingWithUserInput(answer);
return doSomethingWithValue(value);
The API depends on it blocking the main thread, and removing that expectation is effectively just as disruptive as removing the feature entirely: non-abusive usage would have no reason to call this function if not to block for user input. Introducing some magical suspension of the stack like async/await or generators would break assumptions about the entire concurrent execution model of the language (the inverse problem of “colored functions”, infectious async/await etc).The best thing they can do without removing the API is provide an escape hatch, which most browsers already do when alert &co are called multiple times in quick succession.
Why should I as a user have to endure instagram and twitter blocking content with a delayed login prompt that cannot be canceled? Because they can. Browser APIs or not malicious developers will be malicious.
> We can't normalise the attitude that collateral damage is the price of progress, even if we accept the premise — which I don't — that removing APIs like alert represents progress. For all its flaws, the web is generally agreed to be a stable platform, where investments made today will stand the test of time. A world in which websites are treated as inherently transient objects, where APIs we commonly rely on today could be cast aside as unwanted baggage by tomorrow's spec wranglers, is a world in which the web has already lost.
There seems to be a big gap in knowledge when it comes to boundaries between the language specification, runtimes, and innate abilities.
People consistently confused about why they can't use JSX without a build-step, not understanding that JSX isn't "real", why doesn't fetch() work in Node, why does code in my Next.js app break randomly (server vs client render context).
Lot of pain in trying to explain to folks that a browser and Node are two different universes that happen to speak the same general language.
There's too much magic in this ecosystem and not enough emphasis placed on taking the time to understand the tools you work with, IMO.
That's exactly why it's so good that Deno is trying to close the gap. More consistency = fewer surprises
The things that make JS unique aren't even mentioned in a lot of degree programs.
Larry Wall famously said the three virtues of a programmer are impatience, laziness, and hubris. Not learning JS is at the exact intersection where people do all of these at the same time and meet with epic failure. People seem to think to themselves, "I learned Java and this looks like Java, so it must act like java" and so they run down the completely wrong path.
They wouldn't dream of this with C, Java or even python (even though these probably work exactly like other languages they know -- unlike JS), but for some reason perfectly smart developers make this crazy decision all the time.
It's because they can. You can cobble something together and it works or seems to work. It may fail later down the chain but browsers accept all sorts of hackery, because they have been historically doing this for a long time. Before there was Javascript you could write broken HTML, nest elements wrong and browsers still figured out a way to deal with it. The expectations of half-assed solutions has always been there on the web.
Actually it does now! Or it will soon.
https://fusebit.io/blog/node-fetch/?utm_source=www.google.co...
I really hope we will have something like that. It would both give us the option of never using magical globals and make the distinction clear whether the module comes from the language or the runtime. Although I can see a case where it could get annoying if you are writing for multiple runtimes and need to get e.g. fetch (import fetch from "runtime:fetch").
And the right thing to resist doing either. It's to think about what "services" your program actually needs to be able to function and then to isolate those parts from the rest of your application by putting it behind a well-defined interface. In other words, the best way to fix the incompatibility problem caused by API mismatches is to never make the mistake of coding directly against the host platform's APIs to begin with. Trying to do it with compatibility shims to make one platform look like the other is a fool's errand. You end up running around trying to achieve parity with a mammoth API surface area (which might never have been especially well-designed to begin with...).
Let's say you're implementing a program similar in scope to UNIX's file(1). For our example, though, suppose you're really only concerned with text files and specifically whether a given text file is using DOS-style CRLF line separators or UNIX-style LF terminators. You really only need two capabilities: a `read` operation to get the contents of a file and a `print` operation to show the output to the user. Does your program care whether that `read` is happening with a Web standards-backed FileReader or NodeJS's proprietary `fs` module? There's no reason it should. Design the best "system" layer that makes the most sense for your application's needs.
You can see this implementation strategy in the way the TypeScript team wrote the code for the TypeScript compiler itself when it was made public. Even in the early days, it could run on multiple platforms—including NodeJS, JScript/Windows Script Host, and various browsers (old or new)—because it didn't overly concern itself with anything except its real job of lexing, parsing, and type-checking its inputs—wherever they came from—and then writing the output in a platform-agnostic way.
It seems like you're making a good point, but I'm confused by your comment. Do you believe we should avoid coding directly against the host platform's APIs, or do believe we should avoid compatibility shims? At some point, you need compatibility shims in order to avoid coding directly against the host platform's APIs. The most that your runtime strives to match existing runtimes, the less you need to worry about writing shims to improve compatibility.
> Do you believe we should avoid coding directly against the host platform's APIs, or do believe we should avoid compatibility shims?
Avoid compatibility shims that lead to you writing your application's logic directly against platform APIs.
You recognize that you need to read a file, so you write your application logic against the simplest possible interface you can think of that would let you do that: `read`.* You don't try to emulate either platform's API. This sounds like a bad deal, because neither platform provides native support for this interface, and the other approach is tempting, because you already get one implementation of the API for "free" (on whatever platform where that API is native), and you'd "only" have to write the compatibility shim for the other one (or re-use somebody else's shim). This is a mistake. For one thing, people end up misjudging the cost/benefits of each, and for another, the compatibility shim doesn't make the program easier to understand. You end up with quirks of that API infecting increasingly more parts of the program.
* What you don't do is go off and design the best, elaborate, pluggable, most extensible abstraction layer that you can think of. You implement `read`.
I regularly read this advice and I think it's bad in general. If you only ever work against an abstraction, you lose time and might get a worse end result than the one without the abstraction. And in the end, you might throw it away, if it doesn't prove successful. So move the cost for working with an abstraction into the future as much as possible, when you know the alternatives you have to abstract over.
There’s a distinct set of skills and instincts involved in recognizing a generalization of a problem, and a narrower one in recognizing matching solutions which are actually suited to the specific problem. It’s not a skill/instinct everyone has, but it’s not one that should be immediately dismissed either. And one’s recognition of both can grow and be refined over time.
I also think this kind of balanced flexibility should be something we demand as a baseline assumption of the craft:
- We’re going to have instincts no matter what, and we should be encouraged to explore them
- Some of those instincts will prove right, some wrong; often “wrong” will be grey and murky and temporally separated from trying
- When we’ve recognized the error, we should allocate time to correct it with what we’ve learned
- As this process recurses, we should assess whether our predictive senses are getting closer to reality, and adjust our risk impulse accordingly
This is just normal. Is it confusing for a new programmer? Maybe. Is it something they should learn to distinguish? Yes!
I don’t think the answer to this is boolean. For instance:
> I can run C# in Unity. The number of functions I can call is vastly different than running it outside Unity.
If one is learning both in tandem, coming from a background with a language with different scoping rules, knowing the distinction even exists and should be a consideration might not even show up in reading materials. Sure, it’s an important skill to learn, but it’s not especially transferable. I know how it works in some environments and still find it baffling in others where I even know how to read the code. (Example: Java treats methods as locally scoped functions; I still have no idea how to distinguish them without running the code in a debugger. But I don’t write Java! I have a limited understanding of what’s in scope reading it.)
What things aren't like this?