前言:
在我们开发的业务中,有时候不可避免的需要调用一些接口去轮询结果。(原因就是:比如说,我们借助第三方执行下单操作,但是我们需要知道下单后的状态,才能继续我们的下一步流程。因为第三方属于异步,所以不可能迅速获取到下单的状态,这个时候我们就需要轮询,一直到第三方返回具体的成功或者失败结果为止)。
技术栈:
vue3 + js + element plus
开发场景:
本文笔者将根据公司业务里真实的案例进行分析分享。
在调用下单操作的接口后,我们需要再调用轮询接口,去查询下单结果,如果下单成功,那么跳转进入收银台页面,如果失败,抛异常,提醒用户具体失败原因。
状态枚举:
1:结果查询中,未返回 2:下单成功 3:下单失败
轮询思路:
1.因第三方接口属于异步,所以具体返回结果时间不一定,这个时候就需要我们反复调用轮询接口,直到返回具体结果。
2.反复调用接口,要么使用定时器,要么使用递归。因定时器需要设置等待时间,但是具体写入等候时间,并不是很好的选择,同时还要考虑清除定时器的时机。在这里笔者更倾向于递归搭配延时器去操作,当上一次调用返回结果,再去调用下一次接口。
3.调用轮询接口的时候,需要给用户loading提示,但是这里得考虑不能每一次轮询,都用新的loading,否则就会页面一直闪烁,对于用户体验来说,是非常差的。笔者的思路是,针对轮询接口关闭请求拦截器里的loading,然后针对于轮询接口单独写入一个loading,然后轮询开始到轮询结束只用一个loading。
4.得考虑非正常情况下的失败情况,比如500的状态,不能让loading还在那里展示,当异常状态下使用try catch捕获,然后关闭loading,给出提示。
5.轮询次数不能无限制,假设第三方出问题了,一直不返回成功或者失败的状态。我们不可能一直调用接口,一直让页面loading加载。更不能期望于用户去大刷浏览器停止轮询操作。这个时候我们得设置具体的轮询次数,当到达指定的次数,还未获取到正确的结果,则中断轮询,提醒用户下单失败。
具体代码:
let queryLoading = null;
const queryDone = () => {
queryLoading.close();
queryNum = 0;
};
let queryNum = 0;
// 轮询下单结果
const queryResult = async (batchNo) => {
queryNum++;
if (queryNum > 30) {
ElMessage.error("下单失败");
queryDone();
return;
}
queryLoading ??
(queryLoading = ElLoading.service({
lock: true,
target: document.getElementsByClassName("router-view")[0],
text: "拼命加载中",
}));
try {
// 调用轮询订单状态接口
const queyRes = await queryChannelApplyCreateOrderResult({
batchNo,
bizType: params.value.bizType,
});
if (queyRes.data.handlerResult == 2) {
queryDone();
//跳转收银台页面
router.push({
path: "/goods-order/goods-payment",
query: { benefitOrderCode: JSON.stringify([queyRes.data.pcsOrderId]) },
});
} else if (queyRes.data.handlerResult == 3) {
queryDone();
ElMessage.error(queyRes.data.failReason);
return;
} else {
setTimeout(() => {
queryResult(batchNo);
}, 500);
}
} catch (error) {
queryDone();
}
};
tips:采用空合并运算符?? ,是为了能多次轮询只共用一个loading,优化用户体验感
拓展:
程序轮询是什么?
程序轮询(Polling)是一种常见的编程技术,用于定期检查某个条件是否满足。在轮询中,程序会定期执行一个函数或方法,以检查某个条件是否满足,例如检查某个文件是否已经准备好,或者检查某个网络请求是否已经完成。
以下是一个简单的轮询的例子,它每秒检查一次一个变量是否已经达到某个值:
let count = 0;
function checkCount() {
if (count >= 10) {
console.log('Count has reached 10');
clearInterval(intervalId); // 停止轮询
} else {
console.log('Count is still less than 10');
}
}
let intervalId = setInterval(checkCount, 1000); // 每秒执行一次 checkCount 函数
// 模拟 count 的增加
setInterval(() => {
count++;
}, 500);
递归
递归是一种常见的编程技巧,它允许一个函数在其内部调用自身。递归函数通常用于解决可以分解为相似子问题的问题,例如计算阶乘、遍历树或图等。
以下是一个计算阶乘的递归函数的例子:
function factorial(n) {
if (n === 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
console.log(factorial(5)); // 输出 120
轮询和递归有什么不同?
轮询(Polling)和递归(Recursion)是两种不同的编程概念,它们用于解决不同类型的问题,并且它们的工作方式也不同。
“轮询”是一种编程技术,用于定期检查某个条件是否满足。在轮询中,程序会定期执行一个函数或方法,以检查某个条件是否满足,例如检查某个文件是否已经准备好,或者检查某个网络请求是否已经完成。轮询通常用于等待某个条件变为真,但它可能会导致性能问题,因为它会不断地执行函数,即使条件已经满足。
“递归”是一种编程技巧,它允许一个函数在其内部调用自身。递归函数通常用于解决可以分解为相似子问题的问题,例如计算阶乘、遍历树或图等。递归函数需要一个基准情况,以防止无限递归。递归是一种强大的工具,但它也可能会导致性能问题,特别是当问题规模较大时。
总的来说,轮询和递归都是解决特定问题的工具,但它们的工作方式和适用场景是不同的。你应该根据你的具体需求选择最合适的工具。
版权归原作者 零凌林 所有, 如有侵权,请联系我们删除。