Skip to content

Commit 12c363f

Browse files
committed
Address some early feedback in README
1 parent e213837 commit 12c363f

File tree

4 files changed

+30
-16
lines changed

4 files changed

+30
-16
lines changed

README.md

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33

44
Additionally, there are important quantitative performance advantages to JSON and CSS modules over the current equivalents. This document describes these advantages and illustrates them with code samples.
55

6-
## A performance-equivalent JSON module can't be created with JavaScript modules
6+
## A performance-equivalent JSON module can't be built with JavaScript modules
77

88
A naive attempt to replicate the functionality of JSON modules with a JavaScript module wrapper might look something like this:
99

1010
```JavaScript
11-
let responseJSONObject;
11+
let jsonObject;
1212

1313
fetch("./data.json")
1414
.then((response) => {
1515
return response.text();
1616
})
1717
.then((responseText) => {
18-
responseJSONObject = JSON.parse(responseText);
18+
jsonObject = JSON.parse(responseText);
1919
});
2020

21-
export default responseJSONObject;
21+
export default jsonObject;
2222
```
2323

2424
But, because the fetch() completes asynchronously the importer can't safely use the imported JSON object immediately. So, the module can instead export a Promise:
@@ -35,28 +35,43 @@ let responseJSONPromise = fetch("./data.json")
3535
export default responseJSONPromise;
3636
```
3737

38-
Now, however, importers are saddled with the responsibility of waiting for the promise to resolve and of re-exporting the Promise if they want to export dependencies of their own.
38+
Now, however, importers are saddled with the responsibility of waiting for the Promise to resolve, and if they want to export anything that depends on the result of the originally imported Promise they must themselves export a Promise.
3939

40-
These problems will eventually be resolved by [Top-level Await](https://github.com/tc39/proposal-top-level-await) when it becomes standardized.
40+
This necessity to export Promises will eventually be resolved by [Top-level Await](https://github.com/tc39/proposal-top-level-await) when it becomes standardized.
4141
Running with the experimental V8 [--js-flags="--harmony-top-level-await"](https://bugs.chromium.org/p/v8/issues/detail?id=9344),
4242
the simulated JSON module can be written the following way:
4343

4444
```JavaScript
45-
let responseJSONObject;
45+
let jsonObject;
4646

4747
await fetch("./data.json")
4848
.then((response) => {
4949
return response.text();
5050
})
5151
.then((responseText) => {
52-
responseJSONObject = JSON.parse(responseText);
52+
jsonObject = JSON.parse(responseText);
5353
});
5454

55-
export default responseJSONObject;
55+
export default jsonObject;
5656
```
5757

58-
From the perspective of the importer this is ergonomically pretty much equivalent to native JSON
59-
modules. However, static JSON modules can do better performance-wise. In the example above,
58+
or alternatively:
59+
60+
```JavaScript
61+
let response = await fetch("./data2.json")
62+
let responseText = await response.text();
63+
let jsonObject = JSON.parse(responseText);
64+
export default jsonObject;
65+
```
66+
67+
From the perspective of the importer this is ergonomically more or less equivalent to native JSON modules. However it still has these disadvantages:
68+
- The above code snippets take two network requests: the `import` of the wrapper JS module and its `fetch()` of the JSON. A native JSON module just has a single `import` for the JSON.
69+
- JSON module dependencies are resolved statically before module graph evaluation, so if a JSON module fails to load it will block any code in the module graph from running. If a dynamically `fetch()`ed JSON dependency fails to load, part of the module graph could already have executed and caused side-effects.
70+
- Native JSON modules is convenient; it's a bit simpler for devs if they don't have to include the manual `fetch()` and `JSON.parse()` stuff in their code.
71+
72+
And the above depends on the standardization and broad adoption of top-level await. Until that happens, devs are stuck exporting a Promise that the importer needs to deal with.
73+
74+
However, static JSON modules can do better performance-wise. In the example above,
6075
the `fetch()` for data.json doesn't start until the JavaScript in the module executes. This could be delayed by other dependencies in the module graph being slow to load, or by longer executions of other modules that appear earlier in the module graph's execution order.
6176

6277
With JSON modules, on the other hand, browsers can initiate
@@ -68,13 +83,15 @@ the fetch for a JSON file as soon as the importing module is parsed, prior to mo
6883

6984
(The JSON modules demo requires Chrome or Edge launched with --enable-blink-features=JSONModules).
7085

71-
This demo compares two similar custom elements written as a JavaScript module, each of which requires a JSON resource. The first custom element consumes the JSON by `fetch()`ing it, and the second by `import`ing it as a module. For both custom elements, an additional `busyWork.js` module is included in the module graph before the module containing the custom element definition. This is a stand-in for any arbitrary script that might appear in the module graph prior to the custom element definition, such as a JavaScript libary.
86+
This demo compares two similar custom elements written as a JavaScript module, each of which requires a JSON resource. The first custom element consumes the JSON by `fetch()`ing it, and the second by `import`ing it as a module. For both custom elements, an additional `busyWork.js` module is included in the module graph before the module containing the custom element definition. This is a stand-in for any arbitrary script that might appear in the module graph prior to the custom element definition, such as a JavaScript library.
7287

7388
In the `fetch()` version of the custom element, the JSON file isn't fetched until after the code in `busyWork.js` has finished executing, where in the JSON module version of the custom element the JSON file is fetched prior to any script execution. In a real-world scenario where there was network delay in fetching the file, or where there are significant amounts of computation that can only run after the JSON resource is loaded, there could be a significant, user-percieved performance difference.
7489

7590
#### With fetch():
7691
![With fetch](demo1NoModule.PNG)
7792

93+
94+
TODO: Screenshot has tooltip
7895
#### With JSON module:
7996
![With JSON module](demo1Module.PNG)
8097

@@ -98,7 +115,6 @@ Using CSS modules, styles.css is fetched as part of processing the module graph,
98115

99116
If `styles.css` was slow to arrive over the network, or was large enough to take a nontrivial amount of time to parse, front-loading the work could result in a user-percievable difference in how early the styles are applied to the page.
100117

101-
102118
## Demo 3
103119
### [CSS/JSON modules have a lower memory footprint than inlining the CSS/JSON as a JavaScript string](https://dandclark.github.io/json-css-module-notes/demo3/index.html)
104120
[https://dandclark.github.io/json-css-module-notes/demo3/index.html](https://dandclark.github.io/json-css-module-notes/demo3/index.html)

demo1/busyWork.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Eat some cycles
2-
for (let i = 0; i < 1000000; i++) {
2+
for (let i = 0; i < 10000000; i++) {
33
document.createElement("div");
44
}

demo1/module.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@
1111
</head>
1212
<body>
1313
<json-module-test-element></json-module-test-element>
14-
<json-module-test-element></json-module-test-element>
1514
</body>
1615
</html>

demo1/noModule.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@
1111
</head>
1212
<body>
1313
<fetch-test-element></fetch-test-element>
14-
<fetch-test-element></fetch-test-element>
1514
</body>
1615
</html>

0 commit comments

Comments
 (0)