Skip to content
This repository has been archived by the owner on May 17, 2019. It is now read-only.

Commit

Permalink
Use visibility API instead of beforeunload
Browse files Browse the repository at this point in the history
  • Loading branch information
ksheedlo authored and fusion-bot[bot] committed Jan 10, 2019
1 parent 06c721a commit b4c7b85
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The `fusion-plugin-universal-events` is commonly required by other Fusion.js plu

It's useful for when you want to collect data about user actions or other metrics, and send them in bulk to the server to minimize the number of HTTP requests.

For convenience, this plugin automatically flushes its queue on page unload.
For convenience, this plugin automatically flushes its queue before page unload on `document.visibilityState === 'hidden'`.

If you need to use the universal event emitter from React, use [`fusion-plugin-universal-events-react`](https://github.com/fusionjs/fusion-plugin-universal-events-react)

Expand Down
11 changes: 8 additions & 3 deletions src/__tests__/test.browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @flow
*/

/* eslint-env browser */
import test from 'tape-cup';

import App from 'fusion-core';
Expand All @@ -20,6 +21,10 @@ import {
inMemoryBatchStorage as store,
} from '../storage/index.js';

// Set document.visibilityState to test flushBeforeTerminated
Object.defineProperty(document, 'visibilityState', {value: 'hidden'});
const visibilitychangeEvent = new Event('visibilitychange');

/* Test helpers */
function getApp(fetch: Fetch) {
const app = new App('el', el => el);
Expand Down Expand Up @@ -82,7 +87,7 @@ test('Browser EventEmitter', async t => {
emitted = true;
});
emitter.emit('a', {x: 1});
emitter.flush();
window.dispatchEvent(visibilitychangeEvent);
emitter.teardown();
return next();
};
Expand All @@ -107,7 +112,7 @@ test('Browser EventEmitter adds events back to queue if they fail to send', asyn
const emitter = events.from(ctx);
t.equal(emitter, events);
emitter.emit('a', {x: 1});
emitter.flush();
window.dispatchEvent(visibilitychangeEvent);
emitter.teardown();
return next();
};
Expand All @@ -130,7 +135,7 @@ test('Browser EventEmitter adds events back to queue if they fail to send 2', as
const emitter = events.from(ctx);
t.equal(emitter, events);
emitter.emit('a', {x: 1});
emitter.flush();
window.dispatchEvent(visibilitychangeEvent);
emitter.teardown();
return next();
};
Expand Down
8 changes: 5 additions & 3 deletions src/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ class UniversalEmitter extends Emitter {
this.flush = this.flushInternal.bind(this);
this.fetch = fetch;
this.setFrequency(5000);
window.addEventListener('beforeunload', this.flush);
window.addEventListener('visibilitychange', this.flushBeforeTerminated);
}
setFrequency(frequency: number): void {
window.clearInterval(this.interval);
this.interval = setInterval(this.flush, frequency);
this.interval = setInterval(this.flushInternal, frequency);
}
emit(type: mixed, payload: mixed): void {
payload = super.mapEvent(type, payload);
Expand All @@ -50,6 +50,8 @@ class UniversalEmitter extends Emitter {
from(): UniversalEmitter {
return this;
}
flushBeforeTerminated = () =>
document.visibilityState === 'hidden' && this.flushInternal();
async flushInternal(): Promise<void> {
const items = this.storage.getAndClear();
if (items.length === 0) return;
Expand All @@ -73,7 +75,7 @@ class UniversalEmitter extends Emitter {
}
}
teardown(): void {
window.removeEventListener('beforeunload', this.flush);
window.removeEventListener('visibilitychange', this.flushBeforeTerminated);
clearInterval(this.interval);
this.interval = null;
}
Expand Down

0 comments on commit b4c7b85

Please sign in to comment.