js的锁以及异步调用相关
sshong 发表于2024年11月30日 10:58:51 更新于2024年11月30日 11:18:18
js通过引入async await promise来解决异步回调地狱问题。
思考下面的两个场景
注:以下示例代码均用typescript实现

let i = 0;
async function handler() {
    i++;
    console.log(new Date().getTime()/1000, '处理程序开始', i);
    await new Promise(resolve => setTimeout(resolve, 2000)); // 模拟异步操作
    console.log(new Date().getTime()/1000, '处理程序完成', i);
};

场景一:直接调用handler两次
function call1() {
    handler();
    handler();
}
call1();

打印如下:
1732934781.962 处理程序开始 1
1732934781.966 处理程序开始 2
1732934783.969 处理程序完成 2
1732934783.97 处理程序完成 2
可以看出,两次handler都同时先后进入(由于js单线程,i会变化),并同时卡在await等待2s。

场景二:await调用handler两次
async function call2() {
    await handler();
    await handler();
}
call2();

打印如下:
1732934929.563 处理程序开始 1
1732934931.569 处理程序完成 1
1732934931.57 处理程序开始 2
1732934933.571 处理程序完成 2

可以看出,下一次的handler会等上一次执行完毕再进行。

由此可以看出,js如果直接调用函数2次,函数中开头非异步的部分会按调用顺序执行,并同时卡在函数中异步的部分,异步结束后再执行剩余部分。

这很可能造成数据不同步等各种问题。对于要求不管是直接调用还是await调用多次,都要完全保证顺序的地方,需要引入锁机制。

核心就是,函数在进入时立即锁住,即便是直接调用多次,也会确定等待锁释放。
而根据前面的试验结论,可以用一个简单的异步promise来实现这个锁。
let lastlock = Promise.resolve();
async function getlock() {
    let unlock = () => {};
    let lock = lastlock;
    let nlock = new Promise<void>((resolve) => {unlock = resolve;});
    lastlock = nlock;
    await lock;
    return unlock;
}

上面的getlock函数,核心要点
1. lastlock一开始是一个已经resolve的promise,所以await它不会阻塞
2. 每次获取锁,js单线程执行会更改lastlock为一个新的promise,而这个promise的resolve函数会被传出来,也就成了一个unlock函数,这个unlock执行会resolve promise,完成异步。

改造handler函数,用锁
async function handler() {
    const unlock = await getlock();
    try  {
        i++;
        console.log(new Date().getTime()/1000, '处理程序开始', i);
        await new Promise(resolve => setTimeout(resolve, 2000)); // 模拟异步操作
        console.log(new Date().getTime()/1000, '处理程序完成', i);
    } finally {
        unlock();
    }
};

连续直接调用handler两次(即call1())
1732935948.492 处理程序开始 1
1732935950.497 处理程序完成 1
1732935950.497 处理程序开始 2
1732935952.499 处理程序完成 2

连续await调用handler两次(即call2()),打印如下
1732936175.165 处理程序开始 1
1732936177.171 处理程序完成 1
1732936177.171 处理程序开始 2
1732936179.173 处理程序完成 2
标签:promiseasyncawait分类:JS&Html5阅读:154
评论
暂无评论
添加评论
您的大名,限长10汉字,20英文(*)
电子信箱(*)
您的网站
正文,限长500汉字,1000英文(*)
验证码(*) 单击刷新验证码
联系我
博客订阅