Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/third_party/closure/goog/async/nexttick.js
4104 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Provides a function to schedule running a function as soon
9
* as possible after the current JS execution stops and yields to the event
10
* loop.
11
*/
12
13
goog.provide('goog.async.nextTick');
14
15
goog.require('goog.debug.entryPointRegistry');
16
goog.require('goog.dom');
17
goog.require('goog.dom.TagName');
18
goog.require('goog.functions');
19
goog.require('goog.labs.userAgent.browser');
20
goog.require('goog.labs.userAgent.engine');
21
22
23
/**
24
* Fires the provided callbacks as soon as possible after the current JS
25
* execution context. setTimeout(…, 0) takes at least 4ms when called from
26
* within another setTimeout(…, 0) for legacy reasons.
27
*
28
* This will not schedule the callback as a microtask (i.e. a task that can
29
* preempt user input or networking callbacks). It is meant to emulate what
30
* setTimeout(_, 0) would do if it were not throttled. If you desire microtask
31
* behavior, use {@see goog.Promise} instead.
32
*
33
* @param {function(this:SCOPE)} callback Callback function to fire as soon as
34
* possible.
35
* @param {SCOPE=} opt_context Object in whose scope to call the listener.
36
* @param {boolean=} opt_useSetImmediate Avoid the IE workaround that
37
* ensures correctness at the cost of speed. See comments for details.
38
* @template SCOPE
39
*/
40
goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) {
41
'use strict';
42
var cb = callback;
43
if (opt_context) {
44
cb = goog.bind(callback, opt_context);
45
}
46
cb = goog.async.nextTick.wrapCallback_(cb);
47
// Note we do allow callers to also request setImmediate if they are willing
48
// to accept the possible tradeoffs of incorrectness in exchange for speed.
49
// The IE fallback of readystate change is much slower. See useSetImmediate_
50
// for details.
51
if (typeof goog.global.setImmediate === 'function' &&
52
(opt_useSetImmediate || goog.async.nextTick.useSetImmediate_())) {
53
goog.global.setImmediate(cb);
54
return;
55
}
56
57
// Look for and cache the custom fallback version of setImmediate.
58
if (!goog.async.nextTick.nextTickImpl) {
59
goog.async.nextTick.nextTickImpl = goog.async.nextTick.getNextTickImpl_();
60
}
61
goog.async.nextTick.nextTickImpl(cb);
62
};
63
64
65
/**
66
* Returns whether should use setImmediate implementation currently on window.
67
*
68
* window.setImmediate was introduced and currently only supported by IE10+,
69
* but due to a bug in the implementation it is not guaranteed that
70
* setImmediate is faster than setTimeout nor that setImmediate N is before
71
* setImmediate N+1. That is why we do not use the native version if
72
* available. We do, however, call setImmediate if it is a non-native function
73
* because that indicates that it has been replaced by goog.testing.MockClock
74
* which we do want to support.
75
* See
76
* http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10
77
*
78
* @return {boolean} Whether to use the implementation of setImmediate defined
79
* on Window.
80
* @private
81
* @suppress {missingProperties} For "Window.prototype.setImmediate"
82
*/
83
goog.async.nextTick.useSetImmediate_ = function() {
84
'use strict';
85
// Not a browser environment.
86
if (!goog.global.Window || !goog.global.Window.prototype) {
87
return true;
88
}
89
90
// MS Edge has window.setImmediate natively, but it's not on Window.prototype.
91
// Also, there's no clean way to detect if the goog.global.setImmediate has
92
// been replaced by mockClock as its replacement also shows up as "[native
93
// code]" when using toString. Therefore, just always use
94
// goog.global.setImmediate for Edge. It's unclear if it suffers the same
95
// issues as IE10/11, but based on
96
// https://dev.modern.ie/testdrive/demos/setimmediatesorting/
97
// it seems they've been working to ensure it's WAI.
98
if (goog.labs.userAgent.browser.isEdge() ||
99
goog.global.Window.prototype.setImmediate != goog.global.setImmediate) {
100
// Something redefined setImmediate in which case we decide to use it (This
101
// is so that we use the mockClock setImmediate).
102
return true;
103
}
104
105
return false;
106
};
107
108
109
/**
110
* Cache for the nextTick implementation. Exposed so tests can replace it,
111
* if needed.
112
* @type {function(function())}
113
*/
114
goog.async.nextTick.nextTickImpl;
115
116
117
/**
118
* Determines the best possible implementation to run a function as soon as
119
* the JS event loop is idle.
120
* @return {function(function())} The "setImmediate" implementation.
121
* @private
122
*/
123
goog.async.nextTick.getNextTickImpl_ = function() {
124
'use strict';
125
// Create a private message channel and use it to postMessage empty messages
126
// to ourselves.
127
/** @type {!Function|undefined} */
128
var Channel = goog.global['MessageChannel'];
129
// If MessageChannel is not available and we are in a browser, implement
130
// an iframe based polyfill in browsers that have postMessage and
131
// document.addEventListener. The latter excludes IE8 because it has a
132
// synchronous postMessage implementation.
133
if (typeof Channel === 'undefined' && typeof window !== 'undefined' &&
134
window.postMessage && window.addEventListener &&
135
// Presto (The old pre-blink Opera engine) has problems with iframes
136
// and contentWindow.
137
!goog.labs.userAgent.engine.isPresto()) {
138
/** @constructor */
139
Channel = function() {
140
'use strict';
141
// Make an empty, invisible iframe.
142
var iframe = goog.dom.createElement(goog.dom.TagName.IFRAME);
143
iframe.style.display = 'none';
144
document.documentElement.appendChild(iframe);
145
var win = iframe.contentWindow;
146
var doc = win.document;
147
doc.open();
148
doc.close();
149
// Do not post anything sensitive over this channel, as the workaround for
150
// pages with file: origin could allow that information to be modified or
151
// intercepted.
152
var message = 'callImmediate' + Math.random();
153
// The same origin policy rejects attempts to postMessage from file: urls
154
// unless the origin is '*'.
155
var origin = win.location.protocol == 'file:' ?
156
'*' :
157
win.location.protocol + '//' + win.location.host;
158
var onmessage = goog.bind(function(e) {
159
'use strict';
160
// Validate origin and message to make sure that this message was
161
// intended for us. If the origin is set to '*' (see above) only the
162
// message needs to match since, for example, '*' != 'file://'. Allowing
163
// the wildcard is ok, as we are not concerned with security here.
164
if ((origin != '*' && e.origin != origin) || e.data != message) {
165
return;
166
}
167
this['port1'].onmessage();
168
}, this);
169
win.addEventListener('message', onmessage, false);
170
this['port1'] = {};
171
this['port2'] = {
172
postMessage: function() {
173
'use strict';
174
win.postMessage(message, origin);
175
}
176
};
177
};
178
}
179
if (typeof Channel !== 'undefined' && !goog.labs.userAgent.browser.isIE()) {
180
// Exclude all of IE due to
181
// http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
182
// which allows starving postMessage with a busy setTimeout loop.
183
// This currently affects IE10 and IE11 which would otherwise be able
184
// to use the postMessage based fallbacks.
185
var channel = new Channel();
186
// Use a fifo linked list to call callbacks in the right order.
187
var head = {};
188
var tail = head;
189
channel['port1'].onmessage = function() {
190
'use strict';
191
if (head.next !== undefined) {
192
head = head.next;
193
var cb = head.cb;
194
head.cb = null;
195
cb();
196
}
197
};
198
return function(cb) {
199
'use strict';
200
tail.next = {cb: cb};
201
tail = tail.next;
202
channel['port2'].postMessage(0);
203
};
204
}
205
// Fall back to setTimeout with 0. In browsers this creates a delay of 5ms
206
// or more.
207
// NOTE(user): This fallback is used for IE.
208
return function(cb) {
209
'use strict';
210
goog.global.setTimeout(/** @type {function()} */ (cb), 0);
211
};
212
};
213
214
215
/**
216
* Helper function that is overrided to protect callbacks with entry point
217
* monitor if the application monitors entry points.
218
* @param {function()} callback Callback function to fire as soon as possible.
219
* @return {function()} The wrapped callback.
220
* @private
221
*/
222
goog.async.nextTick.wrapCallback_ = goog.functions.identity;
223
224
225
// Register the callback function as an entry point, so that it can be
226
// monitored for exception handling, etc. This has to be done in this file
227
// since it requires special code to handle all browsers.
228
goog.debug.entryPointRegistry.register(
229
/**
230
* @param {function(!Function): !Function} transformer The transforming
231
* function.
232
*/
233
function(transformer) {
234
'use strict';
235
goog.async.nextTick.wrapCallback_ = transformer;
236
});
237
238