async get_(storeName, keys) {
    const op = this.connection_.startReadOnlyOperation(storeName);
    const store = op.store();

    const values = {};
    /** @type {!Array<number>} */
    const missing = [];

    // Use a map to store the objects so that we can reorder the results to
    // match the order of |keys|.
    for (const key of keys) {
      const request = store.get(key);
      request.onsuccess = () => {
        // Make sure a defined value was found. Indexeddb treats no-value found
        // as a success with an undefined result.
        if (request.result == undefined) {
          missing.push(key);
        }

        values[key] = request.result;
      };
    }

    // Wait until the operation completes or else values may be missing from
    // |values|. Use the original key list to convert the map to a list so that
    // the order will match.
    await op.promise();
    if (missing.length) {
      throw new shaka.util.Error(
          shaka.util.Error.Severity.CRITICAL,
          shaka.util.Error.Category.STORAGE,
          shaka.util.Error.Code.KEY_NOT_FOUND,
          'Could not find values for ' + missing);
    }

    return keys.map((key) => values[key]);
  }
@param {string} storeName
@param {!Array<number>} keys
@return {!Promise<!Array<T>>}
@template T
@private