Skip to content

Commit

Permalink
Deduplicate calls to AddEventListener with the same arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
querymetrics authored and nicjansma committed Apr 3, 2018
1 parent 6b19b89 commit 5f2a31a
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 6 deletions.
16 changes: 12 additions & 4 deletions plugins/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -837,10 +837,16 @@
args[callbackIndex] = wrappedFn;

if (functionName === "addEventListener") {
// for removeEventListener we need to keep track of this
// For removeEventListener we need to keep track of this
// unique tuple of target object, event name (arg0), original function
// and capture (arg2)
impl.trackFn(targetObj, args[0], callbackFn, args[2], wrappedFn);
// Since we wrap the origFn with a new anonymous function we can't rely on
// the browser's addEventListener to dedup multiple additions of the same
// callback.
if (!impl.trackFn(targetObj, args[0], callbackFn, args[2], wrappedFn)) {
// if the callback is already tracked, we won't call addEventListener
return;
}
}

return origFn.apply(targetObj, args);
Expand All @@ -860,15 +866,17 @@
* @param {function} listener Original listener
* @param {boolean|object} useCapture|options Use capture flag or options object
* @param {function} wrapped Wrapped function
*
* @returns {boolean} - `true` if function is not already tracked, false otherwise
*/
trackFn: function(target, type, listener, useCapture, wrapped) {
if (!target) {
return;
return false;
}

if (impl.trackedFnIdx(target, type, listener, useCapture) !== -1) {
// already tracked
return;
return false;
}

if (!target._bmrEvents) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
var img8 = new Image(); // "load" tracked then removed several times

function errorFunction1() {
// called 3x from img1,6,7
// called 1x from img1
a.foo1 = false;
}
function errorFunction2() {
Expand Down
86 changes: 86 additions & 0 deletions tests/page-templates/14-errors/23-duplicate-event-listener.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<%= header %>
<%= boomerangScriptMin %>
<script src="23-duplicate-event-listener.js" type="text/javascript"></script>
<script>
BOOMR_test.init({
testAfterOnBeacon: true,
Errors: {
enabled: true,
monitorEvents: true,

// turn off global so it doesn't get in the way
monitorGlobal: false
}
});

var img1 = new Image(); // "load" tracked, capture = false
var img2 = new Image(); // "load" tracked, capture = true
var img3 = new Image(); // "load" tracked, then removed, capture = false
var img4 = new Image(); // "load" tracked, then removed, capture = true
var img5 = new Image(); // "load" tracked using same as img3, then removed, capture = true
var img6 = new Image(); // "load" tracked using same fn as img1, then removed, capture = false
var img7 = new Image(); // "load" tracked using same fn as img1, then removed, capture = true
var img8 = new Image(); // "load" tracked using same fn as img1

function errorFunction1() {
// called 2x from img1,8
a.foo1 = false;
}
function errorFunction2() {
// called 1x from img2
a.foo2 = false;
}
function errorFunction3() {
// called 1x from img5
a.foo3 = false;
}
function errorFunction4() {
// called 1x from img4
a.foo4 = false;
}

if (window.addEventListener) {
img1.addEventListener("load", errorFunction1, false);
img1.addEventListener("load", errorFunction1, false);

img2.addEventListener("load", errorFunction2, true);
img2.addEventListener("load", errorFunction2, true);

img3.addEventListener("load", errorFunction3, false);
img3.addEventListener("load", errorFunction3, false);
// should successfully remove the event
img3.removeEventListener("load", errorFunction3, false);

img4.addEventListener("load", errorFunction4, true);
img4.addEventListener("load", errorFunction4, true);
// no match because capture is different, so the event stays
img4.removeEventListener("load", errorFunction4, false);

img5.addEventListener("load", errorFunction3, true);
img5.addEventListener("load", errorFunction3, true);

img6.addEventListener("load", errorFunction1, false);
img6.addEventListener("load", errorFunction1, false);
img6.removeEventListener("load", errorFunction1, false);

img7.addEventListener("load", errorFunction1, true);
img7.addEventListener("load", errorFunction1, true);
img7.removeEventListener("load", errorFunction1, true);

img8.addEventListener("load", errorFunction1, false);
img8.addEventListener("load", errorFunction1, false);
}

img1.src = "/assets/img.jpg?1";
img2.src = "/assets/img.jpg?2";
img3.src = "/assets/img.jpg?3";
img4.src = "/assets/img.jpg?4";
img5.src = "/assets/img.jpg?5";
img6.src = "/assets/img.jpg?6";
img7.src = "/assets/img.jpg?7";
img8.src = "/assets/img.jpg?8";

</script>
<!-- delay the page by 1second so onloads can fire -->
<img src="/delay?delay=1000&amp;file=/assets/img.jpg" style="width: 100px" />
<%= footer %>
54 changes: 54 additions & 0 deletions tests/page-templates/14-errors/23-duplicate-event-listener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*eslint-env mocha*/
/*global BOOMR_test,assert*/

describe("e2e/14-errors/23-duplicate-event-listener", function() {
var tf = BOOMR.plugins.TestFramework;
var t = BOOMR_test;
var C = BOOMR.utils.Compression;

if (!window.addEventListener) {
it("Skipping on browser that doesn't support addEventListener", function() {
});

return;
}

it("Should have only sent one page load beacon", function(done) {
this.timeout(10000);
t.ensureBeaconCount(done, 1);
});

it("Should have put the err on the page load beacon", function() {
var b = tf.lastBeacon();
assert.isDefined(b.err);
});

it("Should have had 4 errors", function() {
var b = tf.lastBeacon();
assert.equal(C.jsUrlDecompress(b.err).length, 4);
});

it("Should have errorFunction1 have count = 2", function() {
var b = tf.lastBeacon();
var err = BOOMR.plugins.Errors.decompressErrors(C.jsUrlDecompress(b.err))[0];
assert.equal(err.count, 2);
});

it("Should have errorFunction2 have count = 1", function() {
var b = tf.lastBeacon();
var err = BOOMR.plugins.Errors.decompressErrors(C.jsUrlDecompress(b.err))[1];
assert.equal(err.count, 1);
});

it("Should have errorFunction3 have count = 1", function() {
var b = tf.lastBeacon();
var err = BOOMR.plugins.Errors.decompressErrors(C.jsUrlDecompress(b.err))[2];
assert.equal(err.count, 1);
});

it("Should have errorFunction4 have count = 1", function() {
var b = tf.lastBeacon();
var err = BOOMR.plugins.Errors.decompressErrors(C.jsUrlDecompress(b.err))[3];
assert.equal(err.count, 1);
});
});

This file was deleted.

0 comments on commit 5f2a31a

Please sign in to comment.