Files
tubestation/devtools/shared/throttle.js
Alexandre Poirot 62b55667e0 Bug 1824726 - [devtools] Throttle all resources from the server side. r=devtools-reviewers,nchevobbe,perftest-reviewers,sparky
This helps accumulate RDP packets related to resources being available/updated/destroyed
and emit less and larger RDP packets instead or more and smaller.
This appears to reduce the overhead of DevTools transport and JSWindowActor layers.

The issue in browser_markup_events_toggle.js is interesting.
It highlights that a resource notified before a call to WatcherActor.watchResources,
may be emitted during the call to watchResources.
This makes ignoreExistingResources flag a bit brittle as that resource should be
considered as an existing/past one.
We should probably flush past resource and probably introduce a more explicit
way of handling "existing" resources on the server side.

The fix in document-events.js relates to failures in browser_net_offline_mode.js.
This test was passing thanks to late dom-complete event emitted on the previous WindowGlobal.
Surprisingly, when reloading the page in offline mode, the previous, already existing WindowGlobal
triggered the WebProgressListener and we were emitting dom-complete event.
Because of throttling, this resource is no longer transfered to the client as the related target
actor is already destroyed on reload.
But at the end, the issue was the missing dom-interactive and dom-complete events for the error page.

Regarding browser_net_ws-sse-persist-columns.js, it looks like this test was properly waiting
for the WebSocket table to update. We were really lucky it was working without frequent intermittent!

Similarly to the client side, DOCUMENT_EVENT's will-navigate is special
and has to be emitted synchronously in order to prevent clearing things out of order.
This is also true for NETWORK_EVENT_STACKTRACE which is expected to be received
*before* related NETWORK_EVENT. NETWORK_EVENT_STACKTRACE is fired from the content
process while NETWORK_EVENT is fired from the parent process.
For now, it is easier to synchronously emit those resources rather than trying
to do cross process coordination.
We may revisit this choice once we start doing throttling from the parent process
and may be once D143409 lands.

About browser_resources_clear_resources.js, it is surprising it wasn't already failing.

Differential Revision: https://phabricator.services.mozilla.com/D197772
2024-06-10 21:29:00 +00:00

93 lines
2.4 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// setImmediate is only defined when running in the worker thread
/* globals setImmediate */
/**
* From underscore's `_.throttle`
* http://underscorejs.org
* (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Underscore may be freely distributed under the MIT license.
*
* Returns a function, that, when invoked, will only be triggered at most once during a
* given window of time. The throttled function will run as much as it can, without ever
* going more than once per wait duration.
*
* @param {Function} func
* The function to throttle
* @param {number} wait
* The wait period
* @param {Object} scope
* The scope to use for func
* @return {Function} The throttled function
*/
function throttle(func, wait, scope) {
let args, result;
let timeout = null;
let previous = 0;
const later = function () {
previous = Date.now();
timeout = null;
result = func.apply(scope, args);
args = null;
};
const throttledFunction = function () {
const now = Date.now();
const remaining = wait - (now - previous);
args = arguments;
if (remaining <= 0) {
if (!isWorker) {
clearTimeout(timeout);
}
timeout = null;
previous = now;
result = func.apply(scope, args);
args = null;
} else if (!timeout) {
// On worker thread, we don't have access to privileged setTimeout/clearTimeout
// API which wouldn't be frozen when the worker is paused. So rely on the privileged
// setImmediate function which executes on the next event loop.
if (isWorker) {
setImmediate(later);
timeout = true;
} else {
timeout = setTimeout(later, remaining);
}
}
return result;
};
function cancel() {
if (timeout) {
if (!isWorker) {
clearTimeout(timeout);
}
timeout = null;
}
previous = 0;
args = undefined;
result = undefined;
}
function flush() {
if (!timeout) {
return result;
}
previous = 0;
return throttledFunction();
}
throttledFunction.cancel = cancel;
throttledFunction.flush = flush;
return throttledFunction;
}
exports.throttle = throttle;