setupInitialization () {
    const finishInitialization = (result) => {
      this.isInitialized = result

      // We only want to resolve / reject the init promise once during the initialization flow.  Because some trackers
      // do not support reporting "failures" we need to support timeouts that can result in race conditions in some
      // situations.  In these situations we use the first success / fail callback to determine the tracker state and
      // we change the callbacks to noops to prevent later calls from changing the init state.
      this.onInitializeSuccess = () => {}
      this.onInitializeFail = () => {}
    }

    this.initializationCompletePromise = new Promise((resolve, reject) => {
      this.onInitializeSuccess = () => {
        resolve()
        finishInitialization(true)
      }

      this.onInitializeFail = (e) => {
        if (!/init timeout/.test(e.message)) {
          console.error(`${this.constructor.name || 'Tracker'} initialization failed`, e)
        }
        reject(e)
        finishInitialization(false)
      }
    })
  }
Sets up initialization callbacks and top level promise so that
all internal methods can wait on an internal initialize promise.

This must be called from constructor _before_ initialize is called.