From ca6da2fc34b80a90b85a6a0fadcdc0ef570fde5d Mon Sep 17 00:00:00 2001 From: Prateek Srivastava Date: Tue, 21 Feb 2017 17:22:49 -0800 Subject: [PATCH] Add analytics.ready(name, fn) function See https://github.com/segmentio/analytics.js/issues/409 This adds the ability to set a ready callback per integration. todo: * document the function behaviour (need help here on what syntax to use) * test for already readied integration --- lib/analytics.js | 56 ++++++++++++++++++++++++++++++++++++++++-- test/analytics.test.js | 18 ++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/lib/analytics.js b/lib/analytics.js index a974b828..475fb1b0 100644 --- a/lib/analytics.js +++ b/lib/analytics.js @@ -45,6 +45,7 @@ function Analytics() { this.Integrations = {}; this._integrations = {}; this._readied = false; + this._readiedIntegrations = {}; this._timeout = 300; // XXX: BACKWARDS COMPATIBILITY this._user = user; @@ -106,6 +107,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(settings, o this._options(options); this._readied = false; + this._readiedIntegrations = {}; // clean unknown integrations from settings var self = this; @@ -148,8 +150,14 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(settings, o integration.page = after(2, integration.page); } + var integrationReady = function() { + self._readiedIntegrations[integration.name] = true; + self.emit(integration.name + '-ready'); + ready(); + }; + integration.analytics = self; - integration.once('ready', ready); + integration.once('ready', integrationReady); try { integration.initialize(); } catch (e) { @@ -516,6 +524,50 @@ Analytics.prototype.alias = function(to, from, options, fn) { return this; }; +/** + * Register a `fn` to be fired when integrations are ready. + * + * If the first parameter is a function `fn`, `fn` is fired when all + * integrations are ready. + * + * If the first parameter is a string `integration` and the second parameter is + * a function `fn`, `fn` is fired when the given integration is ready. + * + * It is recommended that you use the latter, as the global ready callback may + * not be fired if a single integration fails to load. + * See https://github.com/segmentio/analytics.js/issues/409. + * + * @param {(Function|String)} a Callback function or integration name. + * @param {Function} [b] Callback function. + * @return {Analytics} + */ + +Analytics.prototype.ready = function(a, b) { + if (is.fn(a)) { + return this._ready(a); + } + return this._integrationReady(a, b); +}; + +/** + * Register a `fn` to be fired when the given integration is ready. + * + * @param {String} [name] integration name. + * @param {Function} [fn] Callback function. + * @return {Analytics} + */ + +Analytics.prototype._integrationReady = function(name, fn) { + if (is.fn(fn)) { + if (this._readiedIntegrations[name]) { + nextTick(fn); + } else { + this.once(name + '-ready', fn); + } + } + return this; +}; + /** * Register a `fn` to be fired when all the analytics services are ready. * @@ -523,7 +575,7 @@ Analytics.prototype.alias = function(to, from, options, fn) { * @return {Analytics} */ -Analytics.prototype.ready = function(fn) { +Analytics.prototype._ready = function(fn) { if (is.fn(fn)) { if (this._readied) { nextTick(fn); diff --git a/test/analytics.test.js b/test/analytics.test.js index ba27d72d..b6762a25 100644 --- a/test/analytics.test.js +++ b/test/analytics.test.js @@ -65,6 +65,10 @@ describe('Analytics', function() { assert(analytics._readied === false); }); + it('should setup a _readiedIntegrations object', function() { + assert(type(analytics._readiedIntegrations) === 'object'); + }); + it('should set a default timeout', function() { analytics = new Analytics(); assert(analytics._timeout === 300); @@ -172,6 +176,13 @@ describe('Analytics', function() { assert(!analytics._readied); }); + it('should reset analytics._readiedIntegrations to {}', function() { + analytics.addIntegration(Test); + analytics._readiedIntegrations = { Test: true }; + analytics.initialize(settings); + assert(!analytics._readiedIntegrations.Test); + }); + it('should add integration instance', function(done) { Test.readyOnInitialize(); analytics.addIntegration(Test); @@ -203,6 +214,13 @@ describe('Analytics', function() { analytics.initialize({ Unknown: { key: 'key' } }); }); + it('should listen on integration ready events for integration', function(done) { + Test.readyOnInitialize(); + analytics.addIntegration(Test); + analytics.ready('Test', done); + analytics.initialize(settings); + }); + it('should set analytics._readied to true', function(done) { analytics.ready(function() { assert(analytics._readied);