[英]Promise reject doesn't propagate the error correctly
我收到一個復雜的對象,假設它看起來像這樣:
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;
}
調用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
更加熟悉,因為它們使用與您在同步代碼中習慣使用的相同構造( throw
、 try
、 catch
)。 例如:
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.