Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit 2bd2e13

Browse files
committed
async parsing with load tracking
1 parent df7aea9 commit 2bd2e13

File tree

2 files changed

+95
-16
lines changed

2 files changed

+95
-16
lines changed

src/Parser.js

+77-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
(function(scope) {
88

99
var IMPORT_LINK_TYPE = 'import';
10-
10+
var isIe = /Trident/.test(navigator.userAgent)
1111
// highlander object for parsing a document tree
1212

1313
var importParser = {
@@ -21,16 +21,18 @@ var importParser = {
2121
map: {
2222
link: 'parseLink',
2323
script: 'parseScript',
24-
style: 'parseGeneric'
24+
style: 'parseStyle'
2525
},
2626
// TODO(sorvell): because dynamic imports are not supported, users are
2727
// writing code like in https://github.com/Polymer/HTMLImports/issues/40
2828
// as a workaround. The code here checking for the existence of
2929
// document.scripts is here only to support the workaround.
30-
parse: function(document) {
30+
parse: function(document, done) {
3131
if (!document.__importParsed) {
3232
// only parse once
3333
document.__importParsed = true;
34+
console.group('parsing', scope.path.getDocumentUrl(document));
35+
var tracker = new LoadTracker(document, done);
3436
// all parsable elements in inDocument (depth-first pre-order traversal)
3537
var elts = document.querySelectorAll(importParser.selectors);
3638
// memoize the number of scripts
@@ -48,21 +50,41 @@ var importParser = {
4850
elts = document.querySelectorAll(importParser.selectors);
4951
}
5052
}
53+
console.groupEnd('parsing', scope.path.getDocumentUrl(document));
54+
tracker.open();
55+
} else if (done) {
56+
done();
5157
}
5258
},
5359
parseLink: function(linkElt) {
5460
if (isDocumentLink(linkElt)) {
61+
this.trackElement(linkElt);
5562
if (linkElt.import) {
56-
importParser.parse(linkElt.import);
57-
// fire load event
58-
linkElt.dispatchEvent(new CustomEvent('load'));
63+
importParser.parse(linkElt.import, function() {
64+
// fire load event
65+
linkElt.dispatchEvent(new CustomEvent('load', {bubbles: false}));
66+
});
67+
} else {
68+
linkElt.dispatchEvent(new CustomEvent('error', {bubbles: false}));
5969
}
6070
} else {
6171
this.parseGeneric(linkElt);
6272
}
6373
},
74+
trackElement: function(elt) {
75+
// IE doesn't fire load on style elements
76+
if (!isIe || elt.localName !== 'style') {
77+
elt.ownerDocument.__loadTracker.require(elt);
78+
}
79+
},
80+
parseStyle: function(elt) {
81+
// TODO(sorvell): style element load event can just not fire so clone styles
82+
elt = needsMainDocumentContext(elt) ? cloneStyle(elt) : elt;
83+
this.parseGeneric(elt);
84+
},
6485
parseGeneric: function(elt) {
6586
if (needsMainDocumentContext(elt)) {
87+
this.trackElement(elt);
6688
document.head.appendChild(elt);
6789
}
6890
},
@@ -95,6 +117,55 @@ var importParser = {
95117
}
96118
};
97119

120+
function cloneStyle(style) {
121+
var clone = style.ownerDocument.createElement('style');
122+
clone.textContent = style.textContent;
123+
return clone;
124+
}
125+
126+
function LoadTracker(doc, callback) {
127+
this.doc = doc;
128+
this.doc.__loadTracker = this;
129+
this.callback = callback;
130+
}
131+
132+
LoadTracker.prototype = {
133+
pending: 0,
134+
isOpen: false,
135+
open: function() {
136+
this.isOpen = true;
137+
this.checkDone();
138+
},
139+
add: function() {
140+
this.pending++;
141+
},
142+
require: function(elt) {
143+
this.add();
144+
console.log('require', elt, this.pending);
145+
var names = ['load', 'error'], self = this;
146+
for (var i=0, l=names.length, n; (i<l) && (n=names[i]); i++) {
147+
elt.addEventListener(n, function(e) {
148+
self.receive(e);
149+
});
150+
}
151+
},
152+
receive: function(e) {
153+
this.pending--;
154+
console.log('receive', e.target, this.pending);
155+
this.checkDone();
156+
},
157+
checkDone: function() {
158+
if (!this.isOpen) {
159+
return;
160+
}
161+
if (this.pending <= 0 && this.callback) {
162+
console.log('done!', this.doc, scope.path.getDocumentUrl(this.doc));
163+
this.isOpen = false;
164+
this.callback();
165+
}
166+
}
167+
}
168+
98169
var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
99170

100171
function isDocumentLink(elt) {

src/boot.js

+18-10
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,31 @@
99

1010
// IE shim for CustomEvent
1111
if (typeof window.CustomEvent !== 'function') {
12-
window.CustomEvent = function(inType) {
12+
window.CustomEvent = function(inType, dictionary) {
1313
var e = document.createEvent('HTMLEvents');
14-
e.initEvent(inType, true, true);
14+
e.initEvent(inType,
15+
dictionary.bubbles === false ? false : true,
16+
dictionary.cancelable === false ? false : true,
17+
dictionary.detail);
1518
return e;
1619
};
1720
}
1821

1922
function bootstrap() {
23+
// TODO(sorvell): SD polyfill intrusion
24+
var doc = window.ShadowDOMPolyfill ?
25+
window.ShadowDOMPolyfill.wrapIfNeeded(document) : document;
2026
// preload document resource trees
21-
HTMLImports.importer.load(document, function() {
22-
HTMLImports.parser.parse(document);
23-
HTMLImports.ready = true;
24-
HTMLImports.readyTime = new Date().getTime();
25-
// send HTMLImportsLoaded when finished
26-
document.dispatchEvent(
27-
new CustomEvent('HTMLImportsLoaded', {bubbles: true})
28-
);
27+
HTMLImports.importer.load(doc, function() {
28+
HTMLImports.parser.parse(doc, function() {;
29+
HTMLImports.ready = true;
30+
HTMLImports.readyTime = new Date().getTime();
31+
// send HTMLImportsLoaded when finished
32+
console.warn('firing HTMLImportsLoaded');
33+
doc.dispatchEvent(
34+
new CustomEvent('HTMLImportsLoaded', {bubbles: true})
35+
);
36+
})
2937
});
3038
}
3139

0 commit comments

Comments
 (0)