[whatwg/dom] DOM ready is error prone, still requires libs, could be simpler: a document#ready Promise (#568)

Use case: initializing application code safely (especially dynamically loaded application code).

I think it's common to accidentally write some variant of this code:
```js
window.addEventListener('load', initApp);  // contents of init.js
```
while assuming `load` will always fire and `initApp` will always be called.

However, if init.js runs after the including context's `load` event (i.e. a dynamic script tag added later), `initApp` will never fire as the `load` event has already passed.

This forces web authors to load their scripts earlier to guarantee they're run before the `load` event (which isn't generally great for performance), or third-party widget authors change their code to something like:

```js
function initAppIfReady() {
  var ready = /interactive|loaded/.test(document.readyState);
  if (ready) initApp();
  return ready;
}
if (!initAppIfReady()) {
  document.addEventListener('readystatechange', function f() {
    if (initAppIfReady())
      document.removeEventListener('readystatechange', f);
  });
}
```
to make the code agnostic to how it was loaded.

I see code similar to this being discussed by [Dean Edwards / John Resig in 2006](http://dean.edwards.name/weblog/2006/06/again/) and I'm not aware of a platform solution to this yet.  Sorry if it's already been discussed.

Code like this also lives in [jQuery's src/core/ready.js](https://github.com/jquery/jquery/blob/bd984f0ee2cf40107a669d80d92566b8625b1e6b/src/core/ready.js#L60-L84), a common way to kickstart webapps safely.:
```js
jQuery(document).ready(initApp);  // same as $(initApp)
```

You also see it in [YUI3's `'domready'` event](https://github.com/yui/yui3/blob/master/src/event/js/event-ready-base-ie.js):

```js
YUI().use('event-base', function(Y) {
  Y.on('domready', initApp);
});
```
And a bunch of other popular libraries (including some [simply dedicated to this matter](https://github.com/ded/domready)).

I don't believe `Promise` existed in a useful/standardized way for use in DOM or ECMAScript when building blocks like the `load`, `DOMContentLoaded`, or `readystatechange` events were designed (or `Document#readyState`).  I think this could be _specified_ in a less error prone way.

If `Promise` did exist, I think it'd make a lot of sense to do something like:

```idl
partial interface Document {
  readonly attribute Promise<boolean> ready;
  readonly attribute Promise<boolean> loaded;
};
```

The status of these Promise attributes would be set to resolved by the user agent at an appropriate time (strawman: synchronously in the same turn after handling `readystatechange` to `interactive` or `complete` [respectively] or asynchronously right after?).

Either way, I think encouraging authors/new code to do:

```js
document.ready.then(initApp);
```

is simpler and less error prone and actually what this API strives for to begin with.  DOM libraries could easily check for the existence of this code and use it until it's more standardly supported (and libraries aren't needed at all).

And yes: this can be implemented in terms of existing technology, but so could the `DOMContentLoaded`/`load` events be implemented in terms of polling `Document#readyState` with `setTimeout` (don't mean it's a good idea :wink:).  Here's an example polyfill:

```js
// polyfill Promise if necessary
document.ready = new Promise(function(resolve) {
  function resolveIfReady() {
    var ready = /interactive|loaded/.test(document.readyState);
    if (ready) resolve();
    return ready;
  }
  if (!resolveIfReady()) {
    // could wrap onreadystatechange if really necessary
    document.addEventListener('readystatechange', function f() {
      if (resolveIfReady())
        document.removeEventListener('readystatechange', f);
    });
  }
});
```

If interest is shown in this, I could certainly write web platform tests (and possibly implement in Chrome or find somebody to poke about it).

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/568

Received on Wednesday, 7 February 2018 02:12:59 UTC