在前端开发中我们经常会遇到多个异步任务并发执行的情况,而且有些时候这些任务之间还需要互相配合,如同步某个共享资源。为了解决这类问题,ES2015 推出了 Promise
来处理异步操作,但有些时候我们也需要控制这些异步任务的执行,避免出现竞争条件,这时候可以使用 await-lock
npm 包。
本篇文章主要介绍 await-lock
包的使用,帮助你了解如何用 await-lock
保证多个异步任务的按序执行。
什么是 await-lock?
await-lock
是一个 npm 包,提供了锁操作的支持,可以让异步任务等待锁在获取。它的实现类似于 Java 中的 synchronized
,可以防止出现竞争条件。
如何使用 await-lock?
安装
安装 await-lock
当然可以使用 npm,打开命令行窗口,输入以下命令:
npm install await-lock --save-dev
然后在你的代码中引入 await-lock
:
import { AwaitLock } from 'await-lock';
锁示例
实现基本的锁,可以使用以下代码:
const lock = new AwaitLock(); async function someFunction() { lock.acquireAsync(); // 这里写同步代码 lock.release(); }
我们通过 new AwaitLock()
创建了一个锁实例,并在 someFunction()
异步方法中使用了 lock.acquireAsync()
获取锁,在后面的同步代码执行前,所有尝试获取锁的异步方法都会被阻塞。同样的,我们可以使用 lock.release()
释放锁,让其他阻塞的异步方法继续执行。
读写锁示例
锁有两种常见类型,一种是互斥锁,它只允许有一个执行上下文进入临界区,另一种是读写锁,它可以支持多个读上下文同时进入临界区,但同时只能有一个写上下文在执行。
那么使用 await-lock
如何实现读写锁呢?
我们先来实现一个只支持共享资源互斥访问的锁,如下:
-- -------------------- ---- ------- ------ - --------- - ---- ------------- ----- ---- - --- ------------ ----- ------------- - ------------- - -------- - -- - ----- ------- - ----- -------------------- ----------- --------------- - ----- ------- - ----- -------------------- ---------------------- --------------- - - ----- -------- - --- ---------------- --- ---- - - -- - - --- ---- - ----------------- - ----------------- -- -- --
为了避免竞争条件,我们对 incre()
和 print()
方法分别使用了同一个锁保护对 this.val
的访问。如果一个线程在执行 incre()
,其它线程的 incre()
和 print()
方法都会被阻塞,直到当前线程执行完 release()
。
接下来,我们实现一个读写锁,这个锁支持多个线程同时读取共享资源,但同时只能有一个线程写入。
-- -------------------- ---- ------- ------ - --------- - ---- ------------- ----- ---- - --- ------------ ----- ------------- - ------------- - -------- - -- ------------- - --- ------------ -------------- - --- ------------ ------------ - -- - ----- ------- - ----- ------------------------------ ----------- ------------------------- - ----- ------- - ----- ----------------------------- --------------- -- ------------- --- -- - ----- ------------------------------ - ------------------------ ---------------------- ----- ----------------------------- --------------- -- ------------- --- -- - ------------------------- - ------------------------ - - ----- -------- - --- ---------------- --- ---- - - -- - - --- ---- - ------------- -- - ----------------- -- ------------- - ------ - --- ---- - - -- - - --- ---- - ------------- -- - ----------------- -- ------------- - ------ -
我们在类中添加了两个锁分别用来保护读和写,还新增了一个计数值 readers
,用来记录当前有多少线程正在读取。
在访问 val
的时候,我们首先获取了 readLock
进入读取阶段。如果当前没有其它线程正在读取,那么我们就获取 writeLock
进入写入阶段。所有访问 val
的线程都需要获得 readLock
,一旦访问完成后必须释放锁,以便其它线程访问。当没有线程在读取时,写入线程可以获得 writeLock
,然后更新共享资源,并且释放掉 writeLock
。
总结
本文介绍了 await-lock
包的使用,它提供了一个简单的锁机制,能够保证同一时间只有一个执行上下文进入关键区域执行,从而避免了竞争条件的产生。而且,我们还介绍了如何使用 await-lock
实现读写锁,并提供了代码示例来帮助读者更好的了解如何使用。
希望这篇文章对你有所帮助!
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/70250