listComponents(callback) {
    let promise;
    if (this.processing) {
      promise = this.processing;
    } else if (this.ready && this.components) {
      promise = Promise.resolve(this.components);
    } else {
      this.components = {};
      this.ready = false;
      this.processing = new Promise((resolve, reject) => {
        makeAsync(() => {
          registerLoader.register(this, (err) => {
            if (err) {
              // We keep the failed promise here in this.processing
              reject(err);
              return;
            }
            this.ready = true;
            this.processing = null;
            resolve(this.components);
          });
        });
      });
      promise = this.processing;
    }
    if (callback) {
      deprecated('Providing a callback to ComponentLoader.listComponents is deprecated, use Promises');
      promise.then((components) => {
        callback(null, components);
      }, callback);
    }
    return promise;
  }
@param {any} [callback] - Legacy callback
@returning {Promise<ComponentList>} Promise resolving to list of loaded components