[英]Understand Asynchronous and Promise in NodeJS
在過去的6個月中,我一直在使用NodeJS進行編碼,但是我仍然對異步和Promise概念沒有清晰的了解。 現在,我將使用Mongoose從MongoDB中獲取一條記錄,這可能會使branchId在每次迭代中執行一個簡單的for循環,並執行一個異步的MongoDB操作(因為MongoDB / Mongoose操作是有希望的)。 如您所知,for循環是同步的,但是我的函數在for循環結束之前返回該值。 它是怎么發生的? 如果我的問題不清楚,請附上代碼,以作為評論。
const restManageChef = (params, query, body) => {
if (query && parseBoolean(query.superChef)) {
body = Object.assign(body, { role: 'SUPER-CHEF' });
} else {
body = Object.assign(body, { role: 'RES-CHEF' });
}
return restPUT(params, query, body).then(chef => {
return userModel
.findOne({ restaurantCode: chef.restaurantCode, type: 'RES-ADMIN' })
.then(resAdminDetails => {
log.debug({ Chef: chef }, 'Chef Details');
if (chef.role === 'SUPER-CHEF') {
log.debug({ BranchIds: resAdminDetails.branchIds }, 'BranchIds');
for (let i = 0; i < resAdminDetails.branchIds.length; i) {
log.debug({ BranchIds: resAdminDetails.branchIds[i] }, 'BranchIds');
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({ Restaurant: restaurant }, 'Restaurant Details');
})
.catch(err => {
log.error({ err });
throw err;
});
}
return chef;
} else if (chef.role === 'RES-CHEF') {
for (let i = 0; i < resAdminDetails.branchIds.length; i++) {
log.debug({ BranchIds: resAdminDetails.branchIds[i] }, 'BranchIds');
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({ Restaurant: restaurant }, 'Restaurant Details');
})
.catch(err => {
log.error({ err });
throw err;
});
}
return chef;
}
});
});
};
PushChefId函數
const pushChefId = (restaurantCode, chefId) => {
return userModel
.findOneAndUpdate({ restaurantCode }, { $addToSet: { chefIds: chefId } })
.exec()
.then(resAdmin => {
if (!resAdmin) return Promise.reject(`No RES-ADMIN found with restaurantCode - ${restaurantCode}`);
return storeModel.findByIdAndUpdate(restaurantCode, { $addToSet: { chefIds: chefId } }, { new: true });
});
};
您正在以異步方式使用異步(在您的情況下為Promises)代碼。
這是一個異步調用:
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({
Restaurant: restaurant
}, 'Restaurant Details');
})
.catch(err => {
log.error({
err
});
throw err;
});
基本上,您會逐個觸發此異步調用,然后立即執行return語句,而不必等待每個觸發的異步調用的完成。
我肯定會建議您使用的一種方法是async/await
,它基本上是一種編寫異步代碼的同步方式。
它可能是這樣的:
const decorateWithRole = (query, body) => {
return {
...body,
role: (query && parseBoolean(query.superChef) && "RES-CHEF") || "SUPER-CHEF"
};
};
const restManageChef = async(params, query, body) => {
const decoratedBody = decorateWithRole(query, body, parseBoolean);
const chef = await restPUT(params, query, body);
const resAdminDetails = await userModel.findOne({
restaurantCode: chef.restaurantCode,
type: "RES-ADMIN"
});
log.debug({
Chef: chef
}, "Chef Details");
if (["SUPER-CHEF", "RES-CHEF"].includes(chef.role)) {
log.debug({
BranchIds: resAdminDetails.branchIds
}, "BranchIds");
for (let i = 0; i < resAdminDetails.branchIds.length; i++) {
log.debug({
BranchIds: resAdminDetails.branchIds[i]
}, "BranchIds");
try {
const restaurant = await pushChefId(
resAdminDetails.branchIds[i],
chef.pkid
);
log.debug({
Restaurant: restaurant
}, "Restaurant Details");
} catch (err) {
log.error({
err
});
throw err;
}
}
return chef;
}
};
const pushChefId = async(restaurantCode, chefId) => {
const resAdmin = await userModel
.findOneAndUpdate({
restaurantCode
}, {
$addToSet: {
chefIds: chefId
}
})
.exec();
if (!resAdmin) {
return Promise.reject(
`No RES-ADMIN found with restaurantCode - ${restaurantCode}`
);
}
return storeModel.findByIdAndUpdate(
restaurantCode, {
$addToSet: {
chefIds: chefId
}
}, {
new: true
}
);
};
當然,可以通過並行的Promise觸發等優化它。但是對於基本的解釋應該足夠了。
關鍵的變化在這里:
for (let i = 0; i < resAdminDetails.branchIds.length; i++) {
log.debug({
BranchIds: resAdminDetails.branchIds[i]
}, "BranchIds");
try {
const restaurant = await pushChefId(
resAdminDetails.branchIds[i],
chef.pkid
);
log.debug({
Restaurant: restaurant
}, "Restaurant Details");
} catch (err) {
log.error({
err
});
throw err;
}
}
return chef;
}
};
async
函數上下文中的await
關鍵字將等待Promise
值的解析,並且將在沒有Promise
包裝器的情況下返回該值,而只是返回原始值,否則將收到引發的錯誤,從而允許以同步方式捕獲它。基本try catch
。
希望這可以澄清一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.