Skip to content

Instantly share code, notes, and snippets.

@johnsonjo4531
Last active October 27, 2019 06:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnsonjo4531/99256568deaf8c0f1685793a4a8205bb to your computer and use it in GitHub Desktop.
Save johnsonjo4531/99256568deaf8c0f1685793a4a8205bb to your computer and use it in GitHub Desktop.
AsyncLock implementation

Async Lock

EDIT:

I put my code on code review stack exchange a couple of years back and got this AsyncLock implementation suggested to me which is much less code. Due to it being from stackexchange the code above is licensed (CC-BY-SA 3.0) with attributiton given to blindman67

Original:

P.S. this only works in really modern browsers that support async iterables. Like Chrome 63 (at this point in time Chrome Canary is version 63.)

I saw a comment on Hacker News that said it would be nice to have a lock on variables for async because two things using the same resource can cause problems. Semaphores work for things with more than one resource (you can use a AsyncQueue to do the semaphore pattern. Semaphores and the AsyncQueue are explained in kriskowals GTOR).

My implementation uses the fact that JS is single-threaded so this implementation is likely not thread-safe.

To create a lock I just used the semaphore pattern with only one resource. I subclassed AsyncQueue to add a length variable for the length of available resources in AsyncQueueLength which in AsyncLock I created an AsyncQueue and enforced that it only have one resource max.

The main file is test.js which uses the async lock in AsyncLock.js which uses gtor.js for the AsyncQueue.

// https://codereview.stackexchange.com/questions/177935/asynclock-implementation-for-js
export function AsyncLock() {
const p = () => new Promise(next => (nextIter = next));
var nextIter,
next = p();
const nextP = () => {
const result = next;
next = result.then(() => p());
return result;
};
nextIter();
return Object.assign(
{},
{
async *[Symbol.asyncIterator]() {
try {
yield nextP();
} finally {
nextIter();
}
}
}
);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
</style>
</head>
<body>
<h2>Check your console</h2>
<p>If the lock is working it should print:</p>
<pre>
<code>
here 1a
here 1b
here 2a
here 2b
</code>
</pre>
<script src="test.js" type="module"></script>
</body>
</html>
(CC-BY-SA 3.0)
https://creativecommons.org/licenses/by-sa/3.0/
Attribution: https://codereview.stackexchange.com/users/120556/blindman67
import { AsyncLock } from './AsyncLock.js';
var sleep = (ms)=>new Promise(res=>setTimeout(res, ms));
var lock = new AsyncLock();
(async () => {
for await(var _ of lock) {
console.log("here 1a");
await sleep(1000);
console.log("here 1b")
}
})();
(async () => {
for await(var _ of lock) {
console.log("here 2a");
await sleep(1000);
console.log("here 2b")
}
})();
/*
When Lock is working should print:
here 1a
here 1b
here 2a
here 2b
*/
@johnsonjo4531
Copy link
Author

Here's the block if you want to check the console output without downloading it. https://bl.ocks.org/johnsonjo4531/99256568deaf8c0f1685793a4a8205bb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment