async load({ metadataOnly = false } = {}) {
    try {
      if (!this.isLoaded) {
        if (!this.url) {
          throw new Error('Asset.load: No url, cannot load');
        }

        const url = this.url;
        const protocol = url.substr(0, url.indexOf(':')).toLowerCase();
        if (protocol === 'file') {
          const pathname = urlTools.fileUrlToFsPath(url);
          if (metadataOnly) {
            const stats = await stat(pathname);
            if (stats.isDirectory()) {
              this.fileRedirectTargetUrl = urlTools.fsFilePathToFileUrl(
                pathname.replace(/(\/)?$/, '/index.html')
              );
              // Make believe it's loaded:
              this._rawSrc = Buffer.from([]);
            }
          } else {
            try {
              this._rawSrc = await readFile(pathname);
              this._updateRawSrcAndLastKnownByteLength(this._rawSrc);
            } catch (err) {
              if (err.code === 'EISDIR' || err.code === 'EINVAL') {
                this.fileRedirectTargetUrl = urlTools.fsFilePathToFileUrl(
                  pathname.replace(/(\/)?$/, '/index.html')
                );
                this.isRedirect = true;
              } else {
                throw err;
              }
            }
          }
        } else if (protocol === 'http' || protocol === 'https') {
          const { headers = {}, ...requestOptions } =
            this.assetGraph.requestOptions || {};
          const firstIncomingRelation = this.incomingRelations[0];
          let Referer;

          if (
            firstIncomingRelation &&
            firstIncomingRelation.from.protocol &&
            firstIncomingRelation.from.protocol.startsWith('http')
          ) {
            Referer = firstIncomingRelation.from.url;
          }

          const response = await this.assetGraph.teepee.request({
            ...requestOptions,
            headers: {
              ...headers,
              Referer,
            },
            method: metadataOnly ? 'HEAD' : 'GET',
            url,
            json: false,
          });
          this.statusCode = response.statusCode;
          if (!metadataOnly) {
            this._rawSrc = response.body;
            this._updateRawSrcAndLastKnownByteLength(this._rawSrc);
          }
          if (
            response.headers.location &&
            [301, 302, 303, 307, 308].includes(this.statusCode)
          ) {
            this.location = response.headers.location;
            this.isRedirect = true;
          }
          const contentTypeHeaderValue = response.headers['content-type'];
          if (contentTypeHeaderValue) {
            const matchContentType = contentTypeHeaderValue.match(
              /^\s*([\w\-+.]+\/[\w-+.]+)(?:\s|;|$)/i
            );
            if (matchContentType) {
              this.contentType = matchContentType[1].toLowerCase();

              const matchCharset = contentTypeHeaderValue.match(
                /;\s*charset\s*=\s*(['"]|)\s*([\w-]+)\s*\1(?:\s|;|$)/i
              );
              if (matchCharset) {
                this._encoding = matchCharset[2].toLowerCase();
              }
            } else {
              const err = new Error(
                `Invalid Content-Type response header received: ${contentTypeHeaderValue}`
              );
              err.asset = this;
              this.assetGraph.warn(err);
            }
          } else if (response.statusCode >= 200 && response.statusCode < 300) {
            const err = new Error('No Content-Type response header received');
            err.asset = this;
            this.assetGraph.warn(err);
          }
          if (response.headers.etag) {
            this.etag = response.headers.etag;
          }
          if (response.headers['cache-control']) {
            this.cacheControl = response.headers['cache-control'];
          }
          if (response.headers['content-security-policy']) {
            this.contentSecurityPolicy =
              response.headers['content-security-policy'];
          }
          if (response.headers['content-security-policy-report-only']) {
            this.contentSecurityPolicyReportOnly =
              response.headers['content-security-policy-report-only'];
          }
          for (const headerName of ['date', 'last-modified']) {
            if (response.headers[headerName]) {
              this[
                headerName.replace(/-([a-z])/, ($0, ch) => ch.toUpperCase())
              ] = new Date(response.headers[headerName]);
            }
          }
        } else if (!knownAndUnsupportedProtocols[protocol]) {
          const err = new Error(
            `No resolver found for protocol: ${protocol}\n\tIf you think this protocol should exist, please contribute it here:\n\thttps://github.com/Munter/schemes#contributing`
          );
          if (this.assetGraph) {
            this.assetGraph.warn(err);
          } else {
            throw err;
          }
        }
      }

      // Try to upgrade to a subclass based on the currently available type information:
      this._inferredType = undefined;
      const type = this._inferType();

      this._tryUpgrade(type);

      this.emit('load', this);
      if (this.assetGraph) {
        this.populate(true);
      }
      return this;
    } catch (err) {
      if (!err.message) {
        err.message = err.code || err.name;
      }
      err.asset = this;
      throw err;
    }
  }
Load the Asset

Returns a promise that is resolved when the asset is loaded.
This is Asset's only async method, as soon as it is
loaded, everything can happen synchronously.

Usually you'll want to use `transforms.loadAssets`, which will
handle this automatically.

@async
@return {Promise<Asset>} The loaded Asset