"delay" keyword

# Patrik Stutz (13 years ago)

Today, a really cool idea for a new keyword in JavaScript came to my mind. It's called 'delay'.

What does the delay keyword ?

The delay keyword does nothing more than stop the execution of the current stack and immediately continues to the next task in the queue. But that's not all! Instead of discarding the stack, it adds it to the end of the queue. After all tasks before it are done, the stack continues to execute. What is it good for?

delay could help make blocking code non-blocking while it still looks like synchronous code. A short example:

setTimeout(function(){ console.log("two"); },0); console.log("one"); delay; //since there is currently another task in the queue, do this task first before continuing console.log("three");

//Outputs: one, two, three

This simple keyword would allow us to create a synchronous-looking code wich is asynchronous behind the scenes. Using node.js modules, for example, would no longer be impossible to use in the browser without trickery.

There would be so many possibilites with such a keyword!

What do YOU JAVASCRIPT DEVELOPERS think about it? What do you think can I do to bring this into the new ECMAscript Specification?

Please disuss as much as you want! :)

# Jussi Kalliokoski (13 years ago)

I think the generators address this issue already, to some extent.

But regardless, you might be surprised to find out that this is possible already (without generators), but this is a little secret I've been holding in my pocket, all you'd have change in the example is use something else than setTimeout, and make the delay a function call instead... I'm writing a blog post about it and will be sure to share with the group. ;)

Oh and btw, if there was a keyword like this, I don't think the timeout would always occur during the delay, as setTimeout(..., 0) doesn't necessarily mean now, as opposed to a DOM event such as postMessage or the user clicking somewhere.

# Jussi Kalliokoski (13 years ago)

I have to correct myself; I just realized, you can actually make it a custom keyword instead of a function call. More on this later. ;)

# Tom Van Cutsem (13 years ago)

This idea has been explored before. Some relevant pointers:

Kris Kowal's Q API with experimental support for using generators to write synchronous-style yet asynchronously-executing functions: kriskowal/q/tree/master/examples/async-generators

Strawman for standardization of the above idea: strawman:async_functions

Task.js: cooperative multithreading via generators: taskjs.org

Cheers, Tom

2012/7/4 Patrik Stutz <patrik.stutz at gmail.com>

# Axel Rauschmayer (13 years ago)

Relevant: Why coroutines won't work on the web calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web

Explains why this idea clashes with the run-to-completion semantics of JavaScript and why generators are normally good enough.

# Patrik Stutz (13 years ago)

I've read the articles you linked to and still think that 'delay' would be a great idea! I think thiscalculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web

post is wrong in many things. In my opinion, "coroutines" would be even simpler to implement (depending on the current design of the engine). Also, using generators is complicated as hell and in the end still does nothing useful since "yield" is not asynchronus at all. All the libraries that use generators do a lot to make you feel like it were asynchronous behind the scenes, but it isnt.

Do you really want to add a feature to JavaScript, for that you need a complicated library to use it? And even with such a library, it's still much more complicated to use than a simple "delay" keyword.

While generators & libraries for it would overcomplicate JavaScript, "delay" would be dead simple to use. It would fit much better into the language since the rest of the language is also designed very simple.

all you'd have change in the example is use something else than setTimeout, and make the delay a function call instead..

Cool! But what are the alternatives to "setTimeout" on the browser side wich dont have any delay?

2012/7/4 Jussi Kalliokoski <jussi.kalliokoski at gmail.com>

# David Bruant (13 years ago)

Le 05/07/2012 11:08, Patrik Stutz a écrit :

I've read the articles you linked to and still think that 'delay' would be a great idea! I think this calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web post is wrong in many things. In my opinion, "coroutines" would be even simpler to implement (depending on the current design of the engine).

I am not a JavaScript engine implementors (Dave Herman is, by the way), but from what I know, coroutines would require to store stack frames to enable running them later. If it's not something done already, it may be complicated to do. JavaScript engines are engineered for performance of today's JavaScript and today, there is no coroutine (this probably stands for generators, but some engines already have generators)

Also, using generators is complicated as hell and in the end still does nothing useful since "yield" is not asynchronus at all. All the libraries that use generators do a lot to make you feel like it were asynchronous behind the scenes, but it isnt.

Do you really want to add a feature to JavaScript, for that you need a complicated library to use it? And even with such a library, it's still much more complicated to use than a simple "delay" keyword.

While generators & libraries for it would overcomplicate JavaScript, "delay" would be dead simple to use. It would fit much better into the language since the rest of the language is also designed very simple.

Your post contains a lot of opinions, feelings and things that you think and adding new features is not really about what a particular person thinks in my opinion. For any features to be added to the language, nothing is really about opinion. It all start with use cases. Could you show something that 'delay' enables that is not possible currently? For instance, private names cannot be implemented today and they answer to a need of JavaScript developers who want better encapsulation idioms.

If there is no such thing, is it a major improvement by comparison to what is possible today? For instance, WeakMaps, Maps and Sets can actually be implemented today, but with bad performances or relying on mechanisms with unreliable performance, so having them implemented in the language offers some guarantees of performance.

I am not asking for yes/no answers, but actual code snippets taken out of real projects showing how 'delay' would make the code easier to read or understand, to reason about.

One point made by Dave in his article is very compelling: "Once you add coroutines, you never know when someone might call |yield|. Any function you call has the right to pause and resume you whenever they want". => This makes very difficult to build programs using libraries.

"Generators are a lot like coroutines, with one important difference: they only suspend their own function activation." => And suddenly, your code is not affected by another function being a

generator. When you call a function, it either never return (infinite loop), returns or throws an exception (which is just a different form of return for that matter).

all you'd have change in the example is use something else than setTimeout, and make the delay a function call instead..

Cool! But what are the alternatives to "setTimeout" on the browser side wich dont have any delay?

setTimeout(f ,0) could work, but has a small delay for historical reasons. Microsoft is coming up with setImmediate (I haven't heard anyone following) dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html There is also a trick with calling postMessage to send yourself a message: dbaron.org/log/20100309

# Patrik Stutz (13 years ago)

For any features to be added to the language, nothing is really about opinion. It all start with use cases. Could you show something that 'delay' enables that is not possible currently?

Yes, I can. The reason and main use case why I'm requesting delay is, that I want be able to run node.js modules in the browser without any modification or trickery. I want be able to make a require function that is synchronous but does not block.

With the delay keyword, this would look like this:

function loadModule(name,cb){ setTimeout(function(){ cb({/my aswesome module/}); },0); } function requiure(name){ var module; loadModule(name,function(m){ module = m; }); while(!module){ delay; } return module; }

var myawesomemodule = require("myawesomemodule"); //non-blocking!

With generators, a synchronous but non-blocking require function is simply not possible. You'd have to modify all your code and add everywhere before "require" the "yield" keyword. But that's not all! You'd have to wrap every module definition with another function, which is an absolute pain.

So you see, the node.js module loading problem is not resolvable using generators. So, when such a simple thing is not possible using generators, what are they good fore again?

The fibonacci example on MSD doesn't really point that out. Except code pausing, all that generators can do can also be done otherwise. I've rewirtten the fibonacci example to demonstrate that: function fibonacci(){ var fn1 = 1; var fn2 = 1; return{ next:function(){ var current = fn2; fn2 = fn1; fn1 = fn1 + current; return current; } } }

So, the only "new" thing we got from generators is code pausing. But as we have seen above, this is in the current form also useless, since we are still unable to make node.js like modules possible.

coroutines would require to store stack frames to enable running them later.

This is also true for generators. The only difference is, that the stored stack is never deeper that one function call. So, theoretically, every engine that curently supports "yield" should also be able to store a bigger stack.

But ok, if it's this limitation to flat stacks that excites you about generators, I got another idea how we could mix "delay" and generators to something that makes a lot of sense. What about adding the functions "callDelayed" and "applyDelayed" to the Function prototype? The would do exactly the same as "call" and "apply" but with the difference, that they don't return the result. Instead the return an object that has a synchronous property "result" or a function "getResult()" and a function "continue()". After accessing "result", the code pauses until the function returns a value. In functions, we still would have the "delay" keyword. But instead of moving the current stack to the end of the queue, it would remain paused until someone calls "continue()"

function a(){ delay; return "Hello World"; } var functioncall = a.callDelayed(this); setTimeout(function(){ functioncall.continue(); },0); console.log(functioncall.result); //pauses until "continue()" was called, then displays "Hello World"

To me, all this is not a feeling- or optinion- thing. I just see that I can't do what I want do without co-routines. There's definitely a usecase for them. There are things co-routines can do, that generators can't.

Please note that I'm not really interested in programming new stuff in a new way. I was really happy with the current JavaScript. The only bad thing was, that we were not able to load code synchronously but non-blocking. To make for example node.js modules working in the browser, we needed to rewrite them or to use some trickery. So, I don't wan't to introduce a new coding style with "delay", I just want to make existing code work using some new features.

Generators instead are tought to introduce a new way of coding. But since we were able to do exactly the same in the past using different syntax, it isn't a really needed feature. Except of the code pausing using yieald, tough. * * * *

2012/7/5 David Bruant <bruant.d at gmail.com>

# David Bruant (13 years ago)

Le 05/07/2012 13:36, Patrik Stutz a écrit :

For any features to be added to the language, nothing is really about opinion. It all start with use cases. Could you show something that 'delay' enables that is not possible currently?

Yes, I can. The reason and main use case why I'm requesting delay is, that I want be able to run node.js modules in the browser without any modification or trickery. I want be able to make a require function that is synchronous but does not block.

Maybe that your use case demands a different module system than a new language-level concurrency construct. Have you heard about the module proposal? More interestingly, have you read Isaacs' recent post on the topic? blog.izs.me/post/25906678790/on-es-6-modules I particularly recommend reading the "Next..." section at the end.

# Jussi Kalliokoski (13 years ago)

On Thu, Jul 5, 2012 at 1:04 PM, David Bruant <bruant.d at gmail.com> wrote:

Le 05/07/2012 11:08, Patrik Stutz a écrit :

I've read the articles you linked to and still think that 'delay' would be a great idea! I think thiscalculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web post is wrong in many things. In my opinion, "coroutines" would be even simpler to implement (depending on the current design of the engine).

I am not a JavaScript engine implementors (Dave Herman is, by the way), but from what I know, coroutines would require to store stack frames to enable running them later. If it's not something done already, it may be complicated to do. JavaScript engines are engineered for performance of today's JavaScript and today, there is no coroutine (this probably stands for generators, but some engines already have generators)

Just FYI, SpiderMonkey already has stack pause/resume implemented, I think it has been there at least since Fx8. At least to some extent. What's missing is a way for JS to leverage this (without hacks). Ugh, I really need to write that blog post, this is a very complex subject.

Also, using generators is complicated as hell and in the end still does nothing useful since "yield" is not asynchronus at all. All the libraries that use generators do a lot to make you feel like it were asynchronous behind the scenes, but it isnt.

Do you really want to add a feature to JavaScript, for that you need a complicated library to use it? And even with such a library, it's still much more complicated to use than a simple "delay" keyword.

While generators & libraries for it would overcomplicate JavaScript, "delay" would be dead simple to use. It would fit much better into the language since the rest of the language is also designed very simple.

Your post contains a lot of opinions, feelings and things that you think and adding new features is not really about what a particular person thinks in my opinion. For any features to be added to the language, nothing is really about opinion. It all start with use cases. Could you show something that 'delay' enables that is not possible currently? For instance, private names cannot be implemented today and they answer to a need of JavaScript developers who want better encapsulation idioms.

If there is no such thing, is it a major improvement by comparison to what is possible today? For instance, WeakMaps, Maps and Sets can actually be implemented today, but with bad performances or relying on mechanisms with unreliable performance, so having them implemented in the language offers some guarantees of performance.

I am not asking for yes/no answers, but actual code snippets taken out of real projects showing how 'delay' would make the code easier to read or understand, to reason about.

One point made by Dave in his article is very compelling: "Once you add coroutines, you never know when someone might call yield. Any function you call has the right to pause and resume you whenever they want". => This makes very difficult to build programs using libraries.

"Generators are a lot like coroutines, with one important difference: they only suspend their own function activation." => And suddenly, your code is not affected by another function being a generator. When you call a function, it either never return (infinite loop), returns or throws an exception (which is just a different form of return for that matter).

all you'd have change in the example is use something else than setTimeout, and make the delay a function call instead..

Cool! But what are the alternatives to "setTimeout" on the browser side wich dont have any delay?

setTimeout(f ,0) could work, but has a small delay for historical reasons. Microsoft is coming up with setImmediate (I haven't heard anyone following) dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html There is also a trick with calling postMessage to send yourself a message: dbaron.org/log/20100309-faster-timeouts

David

Yes, the postMessage trick is the one I was referring to, but setImmediate would probably work as well. In node.js, there's process.nextTick(cb), but I don't know of a way to pause/resume a stack in node.

# Patrik Stutz (13 years ago)

Oh I didn't know that Isaac is also unhappy with the whole javascript module thing. I tought that, since there already so much modules for node.js it is pointless to ask them to change their module system, so that node modules also could be used in the browser, so I asked you to give me a JavaScript feature than allows me to implement node's module system in the browser.

But since Isaac is also unhappy, it is likely that he indeed would change the module system of node.js, even if it would mean that all current modules would be broken.

In fact, I'm happy with anything that will solve the current module hell. If we get a built-in module system that node.js also will adopt I don't need my delay keyword anymore.

BUT: interestingly, the import keyword also seems to be synchronous. So, I think behind the scenes there still would have to be something like a "delay" function to make it non-blocking. Or am I missing something?

2012/7/5 David Bruant <bruant.d at gmail.com>

# David Bruant (13 years ago)

Le 05/07/2012 17:19, Patrik Stutz a écrit :

BUT: interestingly, the import keyword also seems to be synchronous. So, I think behind the scenes there still would have to be something like a "delay" function to make it non-blocking. Or am I missing something?

The 'import' keyword is synchronous, but in a different than node.js 'require':

 var a = require('a.js');
 var b = require('b.js');
 var c = require('c.js');

Here, a.js is fetched, parsed and executed, then b.js is fetched, parsed and executed, then c.js is fetched, parsed and executed. In that order sequentially.

 import a from 'a.js'
 import b from 'b.js'
 import c from 'c.js'

Here, a.js, b.js and c.js are fetched and parsed in parallel, but executed in the order they are declared. If other imports are found in parsing phase, these can be fetched and parsed in the background. The most important part being parallel and in depth fetch since network is the performance bottleneck in web applications.

If you want delayed module loading (with a custom delay), you can always fetch the scripts yourself and eval them.

# Wes Garland (13 years ago)

On 5 July 2012 11:19, Patrik Stutz <patrik.stutz at gmail.com> wrote:

Oh I didn't know that Isaac is also unhappy with the whole javascript module thing. I tought that, since there already so much modules for node.js it is pointless to ask them to change their module system, so that node modules also could be used in the browser, so I asked you to give me a JavaScript feature than allows me to implement node's module system in the browser.

I'll bet that there at least 1,000 times more web pages out there that depend on JavaScript's run-to-completion semantics than there are node.js modules.

As for "using Node modules in the browser", provided Node uses CommonJS Modules/1.0 modules (I believe it does), then you might want to look at the draft of a non-standard specification called CommonJS Modules/2.0-draft8 at http:/www.page.ca//~wes/CommonJS/modules-2.0-draft8. To summarize:

  • Works fine on browser
  • Works fine on server
  • Does not alter any semantics of valid /1.1.1 modules
  • Requires a trivial two-line change for each module (and one of those lines is closing brace, close paren, semicolon).

I have implemented most of this spec in BravoJS and it has also been implemented in at least one other project, NobleJS. I have implemented it on the server on top of GPSEE's /1.1.1 module system, with a trivial patch to module.constructor. And I have built two major systems on top of BravoJS + GPSEE using Modules/2.0 modules shared between the browser and the server.

BUT: interestingly, the import keyword also seems to be synchronous. So, I

think behind the scenes there still would have to be something like a "delay" function to make it non-blocking. Or am I missing something?

import is no more synchronous than var. What you are missing is that ES modules do not do demand-based (lazy) loading, like CommonJS can on the server (the spec does not require it, modulo maybe require.paths). All the dependencies in ES modules are statically resolved before any code runs.

Where ES modules differ from current browser-platform module systems derived from CommonJS is that there seems to be no facility to lazy-load modules. Modules/2.0-draft, AMD (require.js), etc, all have some kind of eager module loading, although Modules/2.0 delays initialization to preserve the Modules/1.1.1 execution semantics.

Everybody CommonJS-derived on the client seems to have lazy module loading, too -- but the interesting observation from my POV is that is that lazy module loading on the client seems rather unused. I know I have never used it, and neither has anybody on my team. Has anybody here?

# Brendan Eich (13 years ago)

Patrik Stutz wrote:

I've read the articles you linked to and still think that 'delay' would be a great idea! I think this calculist.org/blog/2011/12/14/why-coroutines-wont-work-on-the-web post is wrong in many things.

Asserting something you don't back up is poor form, at least around es-discuss at mozilla.org.

In my opinion, "coroutines" would be even simpler to implement (depending on the current design of the engine).

This is simply false. Saving one stack frame is always easier to build and optimize (or locally deoptimize) than saving an arbitrary number of stack frames (including ones inlined away by optimizing JITs).

Also, using generators is complicated as hell and in the end still does nothing useful since "yield" is not asynchronus at all. All the libraries that use generators do a lot to make you feel like it were asynchronous behind the scenes, but it isnt.

You need to define your terms. 'yield' does not imply an event loop turn, if "event loop turn" is what you mean by "asynchronous".

That's a benefit: generators are useful for implementing iterators (the easiest way to implement an iterator is by writing a generator). They're a simpler tool.

On Ecma TC39, we do not standardize high-level combinations of primitives that compose neatly. We standardize primitives and let library authors sort out the best combinations on github.com.

If it's obvious what the next higher-layer primitive should be, we standardize quickly. But we do not jump out three or ten moves on the chess board -- that's a good way to lose.

Do you really want to add a feature to JavaScript, for that you need a complicated library to use it?

Yes, as a matter of fact. Many languages (e.g. VB) have gone south with "scenario solving" by adding complex features that are not built on compositional primitives.

And even with such a library, it's still much more complicated to use than a simple "delay" keyword.

Try putting 'delay' deep within a function nest -- nothing simple then in reasoning about data races, what invariants were lost.

While generators & libraries for it would overcomplicate JavaScript, "delay" would be dead simple to use.

Stop asserting something you haven't proven, which has obvious counterexamples.

It would fit much better into the language since the rest of the language is also designed very simple.

Also stop using "very" and "simple" in arguments here. "Very" is deadwood, and you'll need to count entities by some shared way of counting to persuade people of "simple".

all you'd have change in the example is use something else than setTimeout, and make the delay a function call instead..

'delay' cannot be a function call, it must be a special form so engines can analyze for it and deoptimize accordingly.

Cool! But what are the alternatives to "setTimeout" on the browser side wich dont have any delay?

See setImmediate, draft at

dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html

# Patrik Stutz (13 years ago)

Ok, maybe this can indeed work. But instead of the "import x from y" I really would make it like Isaac already suggested it:

var a = import "a.js";

I clearly see the benefit of the "load all at the start before executing anything" strategy and like it very much. I only feared that a site could take a very long time to load when there are big libraries used, even when the page first only displays a login page for example and does only need 1% of the whole code.

But I think one could solve that problem by adding a new script tag after login that contains the next needed module. The cool/bad thing about this is that the developer can decide by himself which modules are loaded at the start and which modules are loaded later. Since lazy module loads are a rare thing, it wouldn't matter if wasn't "synchronous". One should just be able to call Loader.load('mymodule',function(module){}) in this situations. It should also be in the spec, tough.

It would be a perfect combination of load all at once and lazy loading. It could definitely make me happy this way. (With the API suggested by Isaac, tough =))

2012/7/5 David Bruant <bruant.d at gmail.com>

# Brendan Eich (13 years ago)

Patrik Stutz wrote:

Ok, maybe this can indeed work. But instead of the "import x from y" I really would make it like Isaac already suggested it:

var a = import "a.js";

Read esdiscuss/2012-June/023760 and note "control-insensitive".

# Jussi Kalliokoski (13 years ago)

Ok, here's the relevant blog post I mentioned writing: blog.avd.io/posts/js-green-threads . You can discuss / give feedback here or

# Brendan Eich (13 years ago)

Jussi Kalliokoski wrote:

Ok, here's the relevant blog post I mentioned writing: blog.avd.io/posts/js-green-threads, blog.avd.io/posts/js-green-threads . You can discuss / give feedback here or on HackerNews: news.ycombinator.com/item?id=4203749 .

Seems like a bug in Firefox, a violation of HTML5 even. The slow script dialog should not allow an event loop to nest. Cc'ing Boris for his opinion (this may be a known bug on file, my memory dims with age).

Chrome doesn't run onmessage when I continue ("Wait") the Kill-or-Wait sad tab dialog. Safari and Opera (12) seem not to put up a slow script dialog, but perhaps I was impatient (I wanted a minute or so).

# Jussi Kalliokoski (13 years ago)

On Thu, Jul 5, 2012 at 8:50 PM, Brendan Eich <brendan at mozilla.org> wrote:

Jussi Kalliokoski wrote:

Ok, here's the relevant blog post I mentioned writing: blog.avd.io/posts/js-green-**threadsblog.avd.io/posts/js-green-threads< blog.avd.io/posts/js-**green-threadsblog.avd.io/posts/js-green-threads> . You can discuss / give feedback here or on HackerNews: news.ycombinator.com/**item?id=4203749news.ycombinator.com/item?id=4203749.

Seems like a bug in Firefox, a violation of HTML5 even. The slow script dialog should not allow an event loop to nest. Cc'ing Boris for his opinion (this may be a known bug on file, my memory dims with age).

I don't think it's a bug, it seems to meaningful since all the blocking calls have this behaviour. Looks like SM has stack pausing / continuing in place as well; why, if not for this? Seems reasonable to me. But if it's a bug, I'm extremely sorry I haven't filed it, I didn't think it was a bug when I discovered it around Fx8.

Chrome doesn't run onmessage when I continue ("Wait") the Kill-or-Wait sad tab dialog. Safari and Opera (12) seem not to put up a slow script dialog, but perhaps I was impatient (I wanted a minute or so).

Yes, this is Firefox-specific. I've tested all other browsers at my disposal and they don't have this behavior. Seems like a good idea adding it though, could make the browsers a lot more responsive regardless of a few bad websites, and I don't think those websites would break horribly because of this.

# Patrik Stutz (13 years ago)

NICE! Exactly like I requested it :P I also think that this isn't a Bug. It's far to good to be a bug. Such complex things (as you told me it is) like stack pausing/resuming not just are there by accident. It would be really interesting to know what the guys of the V8-Engine think about this.

2012/7/5 Jussi Kalliokoski <jussi.kalliokoski at gmail.com>

# Brendan Eich (13 years ago)

You do realize this works in Firefox via a nested event loop. Not a coroutine or green thread under the hood, by which other events flow in the outer loop?

That makes it a bug, and I am willing to bet real money no other engine will adopt it as a feature.

# Jussi Kalliokoski (13 years ago)

On Thu, Jul 5, 2012 at 9:20 PM, Brendan Eich <brendan at mozilla.org> wrote:

You do realize this works in Firefox via a nested event loop. Not a coroutine or green thread under the hood, by which other events flow in the outer loop?

You mean that all of these blocking calls would accidentally let the event loop continue when they occur, and add continuing the stack to the event loop? Seems like an odd coincidence. What have I done, really sorry not to report this earlier... -.-

That makes it a bug, and I am willing to bet real money no other engine will adopt it as a feature.

If it really is a bug, I have a pretty good guess of how it came to exist, and think this bug is a relevant one: bugzilla.mozilla.org/show_bug.cgi?id=59314 .

# felix (13 years ago)

On Thu, Jul 5, 2012 at 10:50 AM, Brendan Eich <brendan at mozilla.org> wrote:

Jussi Kalliokoski wrote:

Ok, here's the relevant blog post I mentioned writing: blog.avd.io/posts/js-green-**threadsblog.avd.io/posts/js-green-threads< blog.avd.io/posts/js-**green-threadsblog.avd.io/posts/js-green-threads> . You can discuss / give feedback here or on HackerNews: news.ycombinator.com/**item?id=4203749news.ycombinator.com/item?id=4203749.

Seems like a bug in Firefox, a violation of HTML5 even. The slow script dialog should not allow an event loop to nest. Cc'ing Boris for his opinion (this may be a known bug on file, my memory dims with age).

Yes, this is a problem for Caja, and I'm still undecided how to solve it. The slow script dialog can fire at any time; in particular, it can fire when some data structure is in an inconsistent state, and then an event handler firing at the same time might be able to take advantage of that inconsistent state.

"It's a bug in Firefox" seems like the most straightforward answer.

# Oliver Hunt (13 years ago)

I recall in the past having numerous issues with modal dialogs causing unexpected js execution in most engines at least in some edge cases, showModalDialog probably also manages to do it quite effectively.

Basically anytime the engine needs to pump the event loop without allowing any kind of js execution requires the engine to jump through hoops to prevent even handlers. I recall alert(...) with a background asynch xhr being able to trigger such things in the past.

# felix (13 years ago)

I'm not worried about modal dialogs like alert(), because those are explicitly triggered by code, and it's easy to verify that you aren't calling alert inside some critical section. The slow script dialog is a problem because it can happen at any time, so it's difficult to defend against that.

# Brendan Eich (13 years ago)

Boris Zbarsky wrote:

Note that I say "most". There are some fundamental problems here.
Say the user decides to close the tab or window when they get the slow script prompt (something that I think is desirable to allow the user to do, personally). Should this close the tab/window without firing unload events (a spec violation) or should it fire them while other script from the page is on the stack and at some random point in its execution (hey, another spec violation)?

Does the spec really mandate onunload etc. definitely being called in all cases? That is impossible in a great number of cases (machine hard reset, e.g.) and anyway it enables DoS attacks.

Forgenerators in JS1.7 and up, which have a close method that is called when the generator is iterated by a for-in loop (for-of in ES6, I presume), we long ago decided that close may never happen, precisely to prevent DoS problems (accidental, on purpose, doesn't matter).

# Boris Zbarsky (13 years ago)

On 7/5/12 10:37 PM, Brendan Eich wrote:

Does the spec really mandate onunload etc. definitely being called in all cases?

Pretty much, yes. Unless I'm misreading it.

That is impossible in a great number of cases (machine hard reset, e.g.)

Any sort of hardware limitations get Get Out Of Spec Free cards, basically.

and anyway it enables DoS attacks.

Yep. So I doubt anyone will implement the spec on this, if it says what I think it does, and then the spec will get changed.

# Boris Zbarsky (13 years ago)

On 7/5/12 1:50 PM, Brendan Eich wrote:

Seems like a bug in Firefox, a violation of HTML5 even. The slow script dialog should not allow an event loop to nest. Cc'ing Boris for his opinion (this may be a known bug on file, my memory dims with age).

It's a violation of HTML5, but so, technically, is the entire Firefox event loop. HTML5 specifies a very specific set of event queues, and implementing pretty much anything other than exactly that is likely to lead to page-visible spec bugs. Of course the slow script dialog itself is technically a spec violation.....

In any case, I believe we are in the process of moving to a more HTML5-like setup here (with multiple per-page event queues, etc), which should more or less fix most of these issues: we'd just disable all of a page's event queues when the slow script dialog comes up.

Note that I say "most". There are some fundamental problems here. Say the user decides to close the tab or window when they get the slow script prompt (something that I think is desirable to allow the user to do, personally). Should this close the tab/window without firing unload events (a spec violation) or should it fire them while other script from the page is on the stack and at some random point in its execution (hey, another spec violation)?

# Boris Zbarsky (13 years ago)

On 7/5/12 10:37 PM, Brendan Eich wrote:

Does the spec really mandate onunload etc. definitely being called in all cases?

Pretty much, yes. Unless I'm misreading it.

That is impossible in a great number of cases (machine hard reset, e.g.)

Any sort of hardware limitations get Get Out Of Spec Free cards, basically.

and anyway it enables DoS attacks.

Yep. So I doubt anyone will implement the spec on this, if it says what I think it does, and then the spec will get changed.

# Brendan Eich (13 years ago)

Boris Zbarsky wrote:

On 7/5/12 10:37 PM, Brendan Eich wrote:

Does the spec really mandate onunload etc. definitely being called in all cases?

Pretty much, yes. Unless I'm misreading it.

That is impossible in a great number of cases (machine hard reset, e.g.)

Any sort of hardware limitations get Get Out Of Spec Free cards, basically.

And if you take the blue pill and the virtualization Matrix has you?

This is a silly part of the spec. I tried prevailing on Hixie years ago, to no avail. He had some reductionistic view of "hardware" vs. "software", but tiered virtualization (hypervisor or just browser VM) means there must be a way to kill guests cold, without waiting for them to stall with onunload etc.

and anyway it enables DoS attacks.

Yep. So I doubt anyone will implement the spec on this, if it says what I think it does, and then the spec will get changed.

Unimplementable and unimplemented spec is bad spec. Let's fix it. Suggestions welcome -- and maybe a good cop to my bad cop since I failed last time?

# Ian Hickson (13 years ago)

On Thu, 5 Jul 2012, Boris Zbarsky wrote:

It's a violation of HTML5, but so, technically, is the entire Firefox event loop. HTML5 specifies a very specific set of event queues, and implementing pretty much anything other than exactly that is likely to lead to page-visible spec bugs. Of course the slow script dialog itself is technically a spec violation.....

In any case, I believe we are in the process of moving to a more HTML5-like setup here (with multiple per-page event queues, etc), which should more or less fix most of these issues: we'd just disable all of a page's event queues when the slow script dialog comes up.

Note that I say "most". There are some fundamental problems here. Say the user decides to close the tab or window when they get the slow script prompt (something that I think is desirable to allow the user to do, personally). Should this close the tab/window without firing unload events (a spec violation) or should it fire them while other script from the page is on the stack and at some random point in its execution (hey, another spec violation)?

Good points. I have made a note of your e-mail and will in due course ensure that the slow-scripts dialog and harsh termination of a tab are not violations of the HTML spec.

# Ian Hickson (13 years ago)

On Thu, 5 Jul 2012, Boris Zbarsky wrote:

On 7/5/12 1:50 PM, Brendan Eich wrote:

Seems like a bug in Firefox, a violation of HTML5 even. The slow script dialog should not allow an event loop to nest. Cc'ing Boris for his opinion (this may be a known bug on file, my memory dims with age).

[...] Say the user decides to close the tab or window when they get the slow script prompt (something that I think is desirable to allow the user to do, personally). Should this close the tab/window without firing unload events (a spec violation)

That's not a script violation, it's just equivalent to turning off scripts briefly and closing the browsing context.

or should it fire them while other script from the page is on the stack and at some random point in its execution (hey, another spec violation)?

The spec allows user agents to abort scripts (with or without catchable exceptions) upon a timeout or upon user request, so it wouldn't be a spec violation either way.

www.whatwg.org/specs/web-apps/current-work/#killing

# Jussi Kalliokoski (13 years ago)

That explains a lot, I read the spec for that quite a few times to make sure that I didn't misunderstand the case and it seemed to me that it isn't really a spec violation. But it surely isn't desired behavior.