Bluebird、Jasmine 和异步函数未处理的拒绝错误

Unhandled rejection error with Bluebird, Jasmine and an async function

考虑以下(人为的)示例:

import Promise from 'bluebird';

const resolvedPromise = () => {
    return Promise.resolve('Test');
};

const asyncFunc = async (asyncResource) => {
    await resolvedPromise();
    await asyncResource.fetchItem();
};


describe('async/await', () => {
    it('should throw an error', (done) => {
        const mockAsyncResource = jasmine.createSpyObj('mockAsyncResource', ['fetchItem']);

        const mockError = Promise.reject(new Error('HTTP 401 - Access Denied'));

        mockAsyncResource.fetchItem.and.returnValue(mockError);

        return asyncFunc(mockAsyncResource).catch(err => {
            expect(err.message).toEqual('HTTP 401 - Access Denied');
            done();
        });
    });
});

我收到以下输出:

1) async/await
Unhandled rejection Error: HTTP 401 - Access Denied 
... (error stack trace)

✔ should throw an error

规范通过了,但 Bluebird 抱怨未处理的拒绝错误。

由于等待的阻塞性质,mockError 是否会在第二个 await 有机会调用(并处理)mockError 承诺之前报告它是未处理的拒绝?

处理这种情况的最佳方法是什么?我发现了promise.suppressUnhandledRejections(),是不是就这么简单?

我认为这是混合使用 2 种不同类型的 promise 造成的问题。您正在使用蓝鸟的 Promise 创建您的 resolved/rejected 模拟承诺,但等待 returns 原生 Promise.

如果您在 chrome 控制台上尝试以下操作,您将看到它在仅使用本机承诺时按预期工作:

let resolvedPromise = () => {
    return Promise.resolve('Test');
};

let asyncFunc = async (asyncResource) => {
    await resolvedPromise();
    await asyncResource.fetchItem();
};

let mockAsyncResource = {fetchItem: () => Promise.reject(new Error("foo"))};

asyncFunc(mockAsyncResource).catch((e) => console.log('handled'))

如果你想坚持创建 bluebird promises,你可能需要用 bluebird 的 Promise.try 包装你的异步函数,尽管我无法测试这个:

let asyncFunc = async (asyncResource) => {
    return Promise.try(async () => {
        await resolvedPromise();
        await asyncResource.fetchItem();
    });
};