簡體   English   中英

承諾拒絕不會正確傳播錯誤

[英]Promise reject doesn't propagate the error correctly

我收到一個復雜的對象,假設它看起來像這樣:

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

所以,邏輯是,當我收到一個空對象( milk將只是[] ), verifyObject方法將返回 undefined (進一步的邏輯更復雜,必須接收 undefined...); 使用空/未定義對象調用方法時也是如此。

對於牛奶,唯一的驗證應該是這樣的:如果我們有牛奶,那么它需要有quantityexpirationDate ,否則它應該返回 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;
}

調用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的承諾的實現。 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更加熟悉,因為它們使用與您在同步代碼中習慣使用的相同構造( throwtrycatch )。 例如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM