Skip to content

Commit cbdd790

Browse files
committed
Queue up widgets to be initialize manually
This turns out to be faster than making dozens of calls to setTimeout in chrome. Setting up the timers was taking ~15% of our setup time in production
1 parent f4a3fab commit cbdd790

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed

src/index.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import $ from 'jquery';
4949
import { extractOptions } from '@g2crowd/extract-options';
5050
import camelize from './camelize';
51+
import queue from './queue';
5152
import initiationStrategies from './initiationStrategies';
5253
import selectorBuilder from './selectorBuilder';
5354

@@ -59,6 +60,8 @@ class AlreadyRegisteredError extends Error {
5960
}
6061
}
6162

63+
const widgetQueue = queue();
64+
6265
const strategies = initiationStrategies({
6366
nextTick(pluginFn, $$, options, ready) {
6467
return window.setTimeout(() => pluginFn.call($$, options, ready), 0);
@@ -112,7 +115,10 @@ const widget = function({ attr, data }, loadEvents, fragmentLoadEvents) {
112115
extractOptions(data, pluginName)
113116
);
114117

115-
strategies.get(pluginFn.init)(pluginFn, $$, options, ready);
118+
widgetQueue.add(() => {
119+
strategies.get(pluginFn.init)(pluginFn, $$, options, ready);
120+
});
121+
widgetQueue.flush();
116122

117123
$$.data(`vvidget:${name}`, true);
118124
}
@@ -125,8 +131,6 @@ const widget = function({ attr, data }, loadEvents, fragmentLoadEvents) {
125131
const names = `${$$.data(data) || ''} ${$$.attr(attr) || ''}`;
126132

127133
names.split(' ').forEach(name => loadWidget($$, name, $$.data()));
128-
129-
$$.trigger('vvidget:ready');
130134
});
131135
};
132136

src/queue.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// @format
2+
3+
function queue() {
4+
let list = [];
5+
let completed = null;
6+
7+
function flush() {
8+
list.forEach(i => i());
9+
list = [];
10+
}
11+
12+
const me = {
13+
add(item) {
14+
list.push(item);
15+
},
16+
17+
flush() {
18+
if (!completed) {
19+
completed = new Promise(function (resolve) {
20+
window.setTimeout(function () {
21+
flush();
22+
resolve();
23+
}, 0);
24+
});
25+
}
26+
27+
return completed;
28+
},
29+
30+
size() {
31+
return list.length;
32+
}
33+
};
34+
35+
return me;
36+
}
37+
38+
export default queue;

test/camelize.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import camelize from '../src/camelize';
44

5-
test('allows adding strategies', () => {
5+
test('converts strings', () => {
66
expect(camelize('camel_case')).toEqual('camelCase');
77
expect(camelize('camel-case')).toEqual('camelCase');
88
expect(camelize('camelCase')).toEqual('camelCase');

test/queue.test.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @format
2+
3+
import queue from '../src/queue';
4+
5+
test('can add a function', () => {
6+
let q = queue();
7+
8+
q.add(jest.fn());
9+
10+
expect(q.size()).toEqual(1);
11+
});
12+
13+
test('flush calls asynchronously', () => {
14+
let q = queue();
15+
let fn = jest.fn();
16+
q.add(fn);
17+
q.flush();
18+
19+
return q.flush().then(() => {
20+
expect(fn.mock.calls.length).toEqual(1);
21+
});
22+
});
23+
24+
test('flush will run fns added after initial call', () => {
25+
let q = queue();
26+
let fn = jest.fn();
27+
let fn2 = jest.fn();
28+
q.add(fn);
29+
q.flush();
30+
q.add(fn2);
31+
32+
return q.flush().then(() => {
33+
expect(fn2.mock.calls.length).toEqual(1);
34+
});
35+
});

0 commit comments

Comments
 (0)