Skip to main content

自定义hooks解决异步回调问题

问题描述

在回调函数中操作list时候,list更新异常
  • 操作示例
let list = [];
async function callback(data, time) {
const cloneList = [...list];
await new Promise((resolve) => {
setTimeout(() => {
list = [...cloneList, data]
resolve();
}, time);
});
}

callback('a', 1000);
callback('b', 500);

setTimeout(() => {
console.log(list);
}, 1000)

解决方案

使用promise队列构建同步锁
  • Hooks实现
import { useRef } from 'react';

export function useLock() {
const isLockedRef = useRef<boolean>(false);
const queueRef = useRef<any[]>([]);
const acquire = async () => {
return new Promise((resolve) => {
if (!isLockedRef.current) {
isLockedRef.current = true;
resolve(true);
} else {
queueRef.current.push(resolve);
}
});
};

const release = () => {
if (queueRef.current.length > 0) {
const resolve = queueRef.current.shift();
resolve();
} else {
isLockedRef.current = false;
}
};

return {
acquire,
release,
};
}
  • Class实现
class Lock {
constructor() {
this.isLocked = false;
this.queue = [];
}

acquire() {
return new Promise((resolve) => {
if (!this.isLocked) {
this.isLocked = true;
resolve(true);
} else {
this.queue.push(resolve);
}
});
}

release() {
if (this.queue.length > 0) {
const resolve = this.queue.shift();
resolve();
} else {
this.isLocked = false;
}
}
}
  • 使用示例
import React from 'react';

const {acquire, release} = useLock();

let list = [];
async function callback(data, time) {
await lock.acquire();
try {
await new Promise((resolve) => {
const cloneList = [...list];
setTimeout(() => {
list = [...cloneList, data];
resolve();
}, time);
});
} finally {
lock.release();
}
}

callback('a', 1000);
callback('b', 500);