打字稿中的承诺问题

Promise issues in typescript

我一直在用打字稿试验网络音频 API。我正在创建一个 AudioDownloader class 来下载单个或多个音频文件的音频数据和 return 单个或一组承诺。在下载多个音频文件的情况下,我不希望 Promise.all 因为一次失败而失败,所以我使用了一种名为 reflect 的方法(我从网上借来的)。

出于某种原因,由于 return 类型不匹配,download 方法中的打字稿编译失败。在过去的两天里,我一直在努力解决这个问题,但没有运气。我真的不明白我在这里犯了什么错误。有人可以帮忙吗?

class PromiseResult<T> {
    value: T;
    error?: any;
    status: PromiseStatus;
}

enum PromiseStatus {
    Resolved,
    Rejected
}

function reflect<T>(promise: Promise<T>): Promise<PromiseResult<T>> {
    return promise.then(v => {
        return { status: PromiseStatus.Resolved, value: v };
    }, e => {
        return { status: PromiseStatus.Rejected, error: e }
    });
}

type AudioDownloadResult = PromiseResult<AudioBuffer>;

class AudioDownloader {

    private readonly context: AudioContext;

    constructor(context: AudioContext) {
        this.context = context;
    }

    download(urls: string | Array<string>): Promise<AudioDownloadResult | Array<AudioDownloadResult>> {
        if (typeof urls === 'string') {
            return reflect(this.downloadOne(urls as string));
        }

        return Promise.all((<Array<string>>urls).map(this.downloadOne).map(reflect));
    }

    private downloadOne(url: string): Promise<AudioDownloadResult> {
        return new Promise((resolve, reject) => {
            const req = new XMLHttpRequest();
            req.open('GET', url, true);
            req.responseType = 'arraybuffer';
            req.addEventListener('load', () => {
                this.context.decodeAudioData(req.response).then(buffer => {
                    resolve(buffer);
                }, reject);
            }, false);
            req.addEventListener('error', reject, false);
            req.send();
        });
    }
}

我会稍微重构函数并使其按预期工作:

class PromiseResult<T> {
    value: T;
    error?: any;
    status: PromiseStatus;
}

enum PromiseStatus {
    Resolved,
    Rejected
}

type AudioDownloadResult = PromiseResult<AudioBuffer>;

class AudioDownloader {

    private readonly context: AudioContext;

    constructor(context: AudioContext) {
        this.context = context;
    }

    async download(urls: string | Array<string>): Promise<AudioDownloadResult | Array<AudioDownloadResult>>
    {
      try
      {
        if (typeof urls === 'string')
        {
            return await this.downloadOne(urls as string);
        }

        let arr: AudioDownloadResult[] = [];
        for (let url of urls)
        {
          arr.push(await this.downloadOne(url));
        }

        return arr;
      }
      catch (err)
      {
        return { status: PromiseStatus.Rejected, error: err } as AudioDownloadResult;
      }
    }

    private downloadOne(url: string): Promise<AudioDownloadResult> {
        return new Promise((resolve, reject) => {
            const req = new XMLHttpRequest();
            req.open('GET', url, true);
            req.responseType = 'arraybuffer';
            req.addEventListener('load', () => {
                this.context.decodeAudioData(req.response).then(buffer => {
                    resolve(buffer);
                }, reject);
            }, false);
            req.addEventListener('error', reject, false);
            req.send();
        });
    }
}

我还没有测试过 - 但这应该可以。