You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+29-13Lines changed: 29 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -3,22 +3,22 @@
3
3
4
4
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.
5
5
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
7
7
8
8
A naive attempt to replicate the functionality of JSON modules with a JavaScript module wrapper might look something like this:
9
9
10
10
```JavaScript
11
-
letresponseJSONObject;
11
+
letjsonObject;
12
12
13
13
fetch("./data.json")
14
14
.then((response) => {
15
15
returnresponse.text();
16
16
})
17
17
.then((responseText) => {
18
-
responseJSONObject=JSON.parse(responseText);
18
+
jsonObject=JSON.parse(responseText);
19
19
});
20
20
21
-
exportdefaultresponseJSONObject;
21
+
exportdefaultjsonObject;
22
22
```
23
23
24
24
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")
35
35
exportdefaultresponseJSONPromise;
36
36
```
37
37
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.
39
39
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.
41
41
Running with the experimental V8 [--js-flags="--harmony-top-level-await"](https://bugs.chromium.org/p/v8/issues/detail?id=9344),
42
42
the simulated JSON module can be written the following way:
43
43
44
44
```JavaScript
45
-
letresponseJSONObject;
45
+
letjsonObject;
46
46
47
47
awaitfetch("./data.json")
48
48
.then((response) => {
49
49
returnresponse.text();
50
50
})
51
51
.then((responseText) => {
52
-
responseJSONObject=JSON.parse(responseText);
52
+
jsonObject=JSON.parse(responseText);
53
53
});
54
54
55
-
exportdefaultresponseJSONObject;
55
+
exportdefaultjsonObject;
56
56
```
57
57
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 =awaitfetch("./data2.json")
62
+
let responseText =awaitresponse.text();
63
+
let jsonObject =JSON.parse(responseText);
64
+
exportdefaultjsonObject;
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,
60
75
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.
61
76
62
77
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
68
83
69
84
(The JSON modules demo requires Chrome or Edge launched with --enable-blink-features=JSONModules).
70
85
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.
72
87
73
88
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.
74
89
75
90
#### With fetch():
76
91

77
92
93
+
94
+
TODO: Screenshot has tooltip
78
95
#### With JSON module:
79
96

80
97
@@ -98,7 +115,6 @@ Using CSS modules, styles.css is fetched as part of processing the module graph,
98
115
99
116
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.
100
117
101
-
102
118
## Demo 3
103
119
### [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)
0 commit comments