@@ -45,6 +45,7 @@ function Analytics() {
4545 this . Integrations = { } ;
4646 this . _integrations = { } ;
4747 this . _readied = false ;
48+ this . _readiedIntegrations = { } ;
4849 this . _timeout = 300 ;
4950 // XXX: BACKWARDS COMPATIBILITY
5051 this . _user = user ;
@@ -106,6 +107,7 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(settings, o
106107
107108 this . _options ( options ) ;
108109 this . _readied = false ;
110+ this . _readiedIntegrations = { } ;
109111
110112 // clean unknown integrations from settings
111113 var self = this ;
@@ -148,8 +150,14 @@ Analytics.prototype.init = Analytics.prototype.initialize = function(settings, o
148150 integration . page = after ( 2 , integration . page ) ;
149151 }
150152
153+ var integrationReady = function ( ) {
154+ self . _readiedIntegrations [ integration . name ] = true ;
155+ self . emit ( integration . name + '-ready' ) ;
156+ ready ( ) ;
157+ } ;
158+
151159 integration . analytics = self ;
152- integration . once ( 'ready' , ready ) ;
160+ integration . once ( 'ready' , integrationReady ) ;
153161 try {
154162 integration . initialize ( ) ;
155163 } catch ( e ) {
@@ -516,14 +524,58 @@ Analytics.prototype.alias = function(to, from, options, fn) {
516524 return this ;
517525} ;
518526
527+ /**
528+ * Register a `fn` to be fired when integrations are ready.
529+ *
530+ * If the first parameter is a function `fn`, `fn` is fired when all
531+ * integrations are ready.
532+ *
533+ * If the first parameter is a string `integration` and the second parameter is
534+ * a function `fn`, `fn` is fired when the given integration is ready.
535+ *
536+ * It is recommended that you use the latter, as the global ready callback may
537+ * not be fired if a single integration fails to load.
538+ * See https://github.com/segmentio/analytics.js/issues/409.
539+ *
540+ * @param {(Function|String) } a Callback function or integration name.
541+ * @param {Function } [b] Callback function.
542+ * @return {Analytics }
543+ */
544+
545+ Analytics . prototype . ready = function ( a , b ) {
546+ if ( is . fn ( a ) ) {
547+ return this . _ready ( a ) ;
548+ }
549+ return this . _integrationReady ( a , b ) ;
550+ } ;
551+
552+ /**
553+ * Register a `fn` to be fired when the given integration is ready.
554+ *
555+ * @param {String } [name] integration name.
556+ * @param {Function } [fn] Callback function.
557+ * @return {Analytics }
558+ */
559+
560+ Analytics . prototype . _integrationReady = function ( name , fn ) {
561+ if ( is . fn ( fn ) ) {
562+ if ( this . _readiedIntegrations [ name ] ) {
563+ nextTick ( fn ) ;
564+ } else {
565+ this . once ( name + '-ready' , fn ) ;
566+ }
567+ }
568+ return this ;
569+ } ;
570+
519571/**
520572 * Register a `fn` to be fired when all the analytics services are ready.
521573 *
522574 * @param {Function } fn
523575 * @return {Analytics }
524576 */
525577
526- Analytics . prototype . ready = function ( fn ) {
578+ Analytics . prototype . _ready = function ( fn ) {
527579 if ( is . fn ( fn ) ) {
528580 if ( this . _readied ) {
529581 nextTick ( fn ) ;
0 commit comments