feat(utils, payment): add execution lock utils and prevent duplicate payment requests

Add two new throttle utility methods: createAsyncThrottle and createExecutionLock for safe async operation locking. Update the existing throttle method's comment to clarify traditional timestamp usage. Replace DebounceUtils usage with ThrottleUtils.createExecutionLock in order footer and booking page payment handlers to prevent duplicate payments. Rewrite uni.requestPayment calls to use Promise wrapping for proper async handling, and add try/catch/finally blocks to ensure loading state is always cleaned up correctly. Fix template formatting and trailing commas across modified files.
This commit is contained in:
duanshuwen
2026-07-23 21:10:34 +08:00
parent f71f28fe99
commit 34711330bd
3 changed files with 206 additions and 162 deletions

View File

@@ -16,7 +16,7 @@ export class IdUtils {
const timestamp = new Date().getTime();
const chars = "abcdefghijklmnopqrstuvwxyz";
const randomStr = Array.from({ length: 4 }, () =>
chars.charAt(Math.floor(Math.random() * chars.length))
chars.charAt(Math.floor(Math.random() * chars.length)),
).join("");
return "mid" + randomStr + timestamp;
}
@@ -138,7 +138,7 @@ export class MessageUtils {
static createTypewriterMessage(
content,
isComplete = false,
type = "typewriter"
type = "typewriter",
) {
return {
type,
@@ -280,7 +280,7 @@ export class DebounceUtils {
*/
export class ThrottleUtils {
/**
* 创建节流函数
* 创建节流函数(传统时间戳方式)
* @param {Function} func - 要节流的函数
* @param {number} delay - 节流延迟时间
* @returns {Function} 节流后的函数
@@ -297,6 +297,81 @@ export class ThrottleUtils {
}
};
}
/**
* 创建异步安全的节流函数(带执行状态锁)
* 适用于支付等需要等待完成的异步操作
* @param {Function} func - 要节流的异步函数
* @param {number} delay - 节流延迟时间(毫秒)
* @returns {Function} 节流后的函数
*/
static createAsyncThrottle(func, delay = 1000) {
let isExecuting = false; // 执行状态锁
let lastExecTime = 0; // 上次执行时间
return async function (...args) {
const now = Date.now();
// 如果正在执行中,直接返回
if (isExecuting) {
console.warn("函数正在执行中,跳过此次调用");
return;
}
// 如果还在节流时间内,直接返回
if (now - lastExecTime < delay) {
console.warn("节流时间内,跳过此次调用");
return;
}
// 加锁
isExecuting = true;
lastExecTime = now;
try {
// 执行异步函数
return await func.apply(this, args);
} catch (error) {
console.error("异步节流函数执行出错:", error);
throw error;
} finally {
// 无论成功失败都解锁
isExecuting = false;
}
};
}
/**
* 创建执行锁函数(最简单的防重复方式,只锁执行状态)
* 适用于支付等场景,上一次没完成前绝对不执行第二次
* @param {Function} func - 要加锁的函数
* @returns {Function} 加锁后的函数
*/
static createExecutionLock(func) {
let isExecuting = false;
return async function (...args) {
// 如果正在执行中,直接返回
if (isExecuting) {
console.warn("函数正在执行中,跳过此次调用");
return;
}
// 加锁
isExecuting = true;
try {
// 执行函数
return await func.apply(this, args);
} catch (error) {
console.error("执行锁函数执行出错:", error);
throw error;
} finally {
// 无论成功失败都解锁
isExecuting = false;
}
};
}
}
/**