承诺打字稿中的问题

时间:2017-01-19 11:07:03

标签: typescript web-audio es6-promise

我一直在试用带有打字稿的Web Audio API。我正在创建一个AudioDownloader类,用于下载单个或多个音频文件的音频数据,并返回一个或一组promises。在下载多个音频文件的情况下,我不希望Promise.all由于单个故障而失败,所以我使用了一个名为reflect的方法(我从网上借来的)。

由于某些原因,由于返回类型不匹配,打字稿编译在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();
        });
    }
}

1 个答案:

答案 0 :(得分:1)

我会稍微重构函数并通过这样做让它按预期工作:

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();
        });
    }
}

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