【问题标题】:Promise reject doesn't propagate the error correctly承诺拒绝没有正确传播错误
【发布时间】:2020-08-25 08:22:54
【问题描述】:

我收到一个复杂的对象,假设它看起来像这样:

complexObject: {
    fruits: string[],
    vegetables: string[],
    milk: [] | [{
        expirationDate: string,
        quantity: string
    }]
}

所以,逻辑是,当我收到一个空对象(milk 将只是[])时,verifyObject 方法将返回 undefined(进一步的逻辑更复杂,必须接收 undefined.. .);使用空/未定义对象调用方法时也是如此。

对于牛奶,唯一的验证应该是这样的: 如果我们有牛奶,那么它需要同时具有quantity 和expirationDate,否则它应该返回 false。 问题是,当我发送这样的对象时:

{
    'fruits': ['apples', 'bananas'],
    'vegetables': ['tomatoes'],
    'milk': [{
        'quantity': '10'
    }]
}

在checkAndAssign 方法中,它会看到错误,打印console.log,但它不会停在那里,它会将对象添加到result。 另外,在verifyObject方法中,会进入catch块,但upper不会抛出错误,而是解析promise,返回结果...

我想在收到错误消息时停止执行并传播错误...

这是代码:

verifyObject(complexObject) {
    return new Promise((resolve, reject) => {
        const result = {};
        const propertiesEnum = ['fruits', 'vegetables', 'milk'];

        if (!complexObject) {
            resolve({ result: undefined });
        } else {
            this.checkAndAssign(complexObject, result)
                .catch((err) => {
                    console.log('enter error');
                    reject({ message: err });
                })
            if (!Object.keys(result).length) {
                console.log('resolve with undefined');
                resolve({ result: undefined });
            }
            console.log('resolve good');
            resolve({ result });
        }

    })
}

private checkAndAssign(complexObject, result) {
    return new Promise((resolve, reject) => {
        for (const property of complexObject) {
            if(complexObject[property] && Object.keys(complexObject[property]).length)
            if(property === 'milk' && this.verifyMilk(complexObject[property]) === false) {
                console.log('rejected');
                reject('incomplete');
            }
            Object.assign(result, {[property]: complexObject[property]})
            console.log('result is...:>', result);
        }
        console.log('final result:>', result);
        resolve(result);
    });
}

private verifyMilk(milk:any): boolean {
    for(const item of milk) {
        if(!(item['expirationDate'] && item['quantity'])) {
            return false;
        }
    }
    return true;
}

【问题讨论】:

  • checkPropertyAndAssignValue 是否会执行上面未显示的异步操作?

标签: javascript typescript error-handling promise


【解决方案1】:

调用reject 不会终止你调用它的函数。 reject 只是一个普通的函数调用。调用完成后,调用它的函数将继续。

如果您不想这样,请使用return:

private checkPropertyAndAssignValue(complexObject, result) {
    return new Promise((resolve, reject) => {
        for (const property of complexObject) {
            if(complexObject[property] && Object.keys(complexObject[property]).length)
            if(property === 'milk' && this.verifyMilk(complexObject[property]) === false) {
                console.log('rejected');
                reject('incomplete');
                return; // <================================================ here
            }
            Object.assign(result, {[property]: complexObject[property]})
            console.log('result is...:>', result);
        }
        console.log('final result:>', result);
        resolve(result);
    });
}

那么verifyObject需要等待来自checkPropertyAndAssignValue的promise的实现。 verifyObject 的代码成为显式承诺创建反模式的牺牲品:它不应该使用new Promise,因为它已经有来自checkPropertyAndAssignValue 的承诺。避免反模式也有助于避免这个错误:

verifyObject(complexObject) {
    const result = {};
    const propertiesEnum = ['fruits', 'vegetables', 'milk'];

    if (!complexObject) {
        return Promise.resolve({ result: undefined });
    }

    return this.checkPropertyAndAssignValue(complexObject, result)
        .then(() => {
            if (!Object.keys(result).length) {
                console.log('resolve with undefined');
                return { result: undefined };
            }
            console.log('resolve good');
            return { result };
        })
        .catch((err) => {
            console.log('enter error');
            throw { message: err }; // *** Will get caught by the promise mechanism and turned into rejection
        });
}

作为替代方案:如果您正在为现代环境编写此代码,您可能会发现 async 函数和 await 更熟悉,因为它们使用相同的构造(throw、try、@ 987654335@),您习惯于使用同步代码。例如:

async verifyObject(complexObject) {
    const result = {};
    const propertiesEnum = ['fruits', 'vegetables', 'milk'];

    if (!complexObject) {
        return { result: undefined };
    }

    try {
        await this.checkPropertyAndAssignValue(complexObject, result);
//      ^^^^^−−−−− waits for the promise to settle
        if (!Object.keys(result).length) {
            console.log('return undefined');
            return { result: undefined };
        }
        console.log('return good');
        return { result };
    } catch (err) {
        console.log('enter error');
        throw { message: err }; // *** FWIW, suggest making all rejections Error instances
                                // (even when using promises directly)
    }
}

private async checkPropertyAndAssignValue(complexObject, result) {
    // *** Note: This used to return a promise but didn't seem to have any asynchronous
    //     code in it. I've made it an `async` function, so if it's using something
    //     that returns a promise that you haven't shown, include `await` when getting
    //     its result.
    for (const property of complexObject) {
        if(complexObject[property] && Object.keys(complexObject[property]).length)
        if(property === 'milk' && this.verifyMilk(complexObject[property]) === false) {
            throw 'incomplete'; // *** FWIW, suggest making all rejections Error instances
                                // (even when using promises directly)
        }
        Object.assign(result, {[property]: complexObject[property]})
        console.log('result is...:>', result);
    }
    console.log('final result:>', result);
    return result;
}

【讨论】:

  • 假设我不能使用 async-await 或 throw... 我试过只在 checkPropertyAndAssignValue 方法中添加 return 并且它不会添加牛奶(因为它是错误的),但是在verifyObject 中它会返回对象然后进入catch 块...所以verifyObject 会返回一个值并且不会传播错误
  • @rocko - 是的,verifyObject 需要使用 then 处理程序。我会更新的。 (有趣的提示:该问题已使用 async 函数自动修复。这是他们强大的一部分。)
  • @rocko - 我已经更新以展示如何修复 verifyObject。 :-) 但请务必在对问题的评论中回答我的问题。
  • 显然then 处理程序修复了剩下的所有内容:) 我什至没有看到那个...也许只是因为疲倦...无论如何,谢谢你一百万次! ! :D
猜你喜欢
  • 2020-07-06
  • 2017-10-15
  • 2018-10-22
  • 1970-01-01
  • 2020-06-06
  • 2022-12-04
  • 2015-04-13
  • 1970-01-01
  • 2019-12-22
相关资源
最近更新 更多