@dxos/async
Advanced tools
Comparing version 1.0.0-beta.10 to 1.0.0
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -8,2 +8,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
const trigger_1 = require("./trigger"); | ||
// TODO(burdon): Remove. | ||
exports.noop = (...args) => args; | ||
@@ -10,0 +11,0 @@ /** |
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -5,0 +5,0 @@ Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
// | ||
// Copyright 2020 DXOS.org | ||
// | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -219,3 +222,4 @@ exports.Event = void 0; | ||
catch (err) { | ||
console.log(`Unhandled error in Event listener: ${err}`); | ||
console.error('Unhandled error in Event listener:'); | ||
console.error(err); | ||
} | ||
@@ -222,0 +226,0 @@ }); |
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -5,0 +5,0 @@ Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -5,0 +5,0 @@ var __importDefault = (this && this.__importDefault) || function (mod) { |
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -5,0 +5,0 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
"use strict"; | ||
// | ||
// Copyright 2020 DXOS.org | ||
// | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -3,0 +6,0 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; |
/** | ||
* A locking meachnism to ensure that a given section of the code is executed by only a single "thread" at a time. | ||
* | ||
* # How it works | ||
* | ||
* Functions are chained in a structure similar to a linked list. `_lastPromise` always contains the function | ||
* that will finish executing last. Initially it is set to `Promise.resolve()` - promise that resolves immediately. | ||
* Enqueing is done by attaching provided function to the `_lastPromise` via a `.then()` call and updating | ||
* the `_lastPromise` variable. It is important that enquing is done atomically: there are no `await`s in `executeSynchronized` | ||
* and it's not async while still returning a promise. | ||
* the `_lastPromise` variable. It is important that enquing is done atomically: there are no `await`s in | ||
* `executeSynchronized` and it's not async while still returning a promise. | ||
* | ||
* Java docs reference on synchronized sections: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html | ||
* Java docs reference on synchronized sections: | ||
* https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html | ||
*/ | ||
@@ -14,0 +13,0 @@ export declare class Lock { |
"use strict"; | ||
// | ||
// Copyright 2020 DXOS.org | ||
// | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.synchronized = exports.Lock = void 0; | ||
const trigger_1 = require("./trigger"); | ||
/** | ||
* A locking meachnism to ensure that a given section of the code is executed by only a single "thread" at a time. | ||
* | ||
* # How it works | ||
* | ||
* Functions are chained in a structure similar to a linked list. `_lastPromise` always contains the function | ||
* that will finish executing last. Initially it is set to `Promise.resolve()` - promise that resolves immediately. | ||
* Enqueing is done by attaching provided function to the `_lastPromise` via a `.then()` call and updating | ||
* the `_lastPromise` variable. It is important that enquing is done atomically: there are no `await`s in `executeSynchronized` | ||
* and it's not async while still returning a promise. | ||
* the `_lastPromise` variable. It is important that enquing is done atomically: there are no `await`s in | ||
* `executeSynchronized` and it's not async while still returning a promise. | ||
* | ||
* Java docs reference on synchronized sections: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html | ||
* Java docs reference on synchronized sections: | ||
* https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html | ||
*/ | ||
@@ -30,10 +33,20 @@ class Lock { | ||
*/ | ||
executeSynchronized(fun) { | ||
const promise = this._lastPromise.then(() => fun()); | ||
this._lastPromise = promise.then(() => { }, () => { }); | ||
return promise; | ||
async executeSynchronized(fun) { | ||
const prevPromise = this._lastPromise; | ||
// Immediately update the promise before invoking any async actions so that next invocation waits for our task to complete. | ||
const [getPromise, resolve] = trigger_1.trigger(); | ||
this._lastPromise = getPromise(); | ||
await prevPromise; | ||
try { | ||
const value = await fun(); | ||
return value; | ||
} | ||
finally { | ||
resolve(); | ||
} | ||
} | ||
} | ||
exports.Lock = Lock; | ||
const classLockSymbol = Symbol('classLock'); | ||
// TODO(burdon): Document. | ||
const classLockSymbol = Symbol('class-lock'); | ||
/** | ||
@@ -40,0 +53,0 @@ * Same as `synchronized` in Java. |
"use strict"; | ||
// | ||
// Copyright 2020 DXOS.org | ||
// | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
@@ -46,4 +49,4 @@ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
'lock2', | ||
'lock3', | ||
'p1 resolve', | ||
'lock3', | ||
'p2 resolve', | ||
@@ -76,2 +79,23 @@ 'after' | ||
}); | ||
test('errors are propagated with stack traces', async () => { | ||
const lock = new lock_1.Lock(); | ||
async function throwsError() { | ||
throw new Error(); | ||
} | ||
let error; | ||
async function callLock() { | ||
try { | ||
await lock.executeSynchronized(async () => { | ||
await throwsError(); | ||
}); | ||
} | ||
catch (err) { | ||
error = err; | ||
throw error; | ||
} | ||
} | ||
await expect(() => callLock()).rejects.toThrowError(); | ||
expect(error.stack.includes('throwsError')).toBe(true); | ||
expect(error.stack.includes('callLock')).toBe(true); | ||
}); | ||
}); | ||
@@ -78,0 +102,0 @@ class TestClass { |
"use strict"; | ||
// | ||
// Copyright 2020 DXOS.org | ||
// | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -3,0 +6,0 @@ exports.sink = void 0; |
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -5,0 +5,0 @@ Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
// | ||
// Copyright 2020 DxOS | ||
// Copyright 2020 DXOS.org | ||
// | ||
@@ -5,0 +5,0 @@ Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
// | ||
// Copyright 2020 DXOS.org | ||
// | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -18,3 +21,2 @@ exports.Trigger = exports.useValue = exports.trigger = void 0; | ||
exports.trigger = trigger; | ||
// TODO(burdon): Remove. | ||
/** | ||
@@ -24,2 +26,3 @@ * Use `trigger` instead. | ||
*/ | ||
// TODO(burdon): Remove. | ||
exports.useValue = trigger; | ||
@@ -26,0 +29,0 @@ /** |
{ | ||
"name": "@dxos/async", | ||
"version": "1.0.0-beta.10", | ||
"version": "1.0.0", | ||
"description": "Basic async utils", | ||
@@ -17,2 +17,3 @@ "files": [ | ||
"lint": "eslint 'src/**/*.{js,ts}'", | ||
"lint:lockfile": "lockfile-lint --path yarn.lock --allowed-hosts yarn npm codeload.github.com --validate-https", | ||
"prepublishOnly": "npm run test && npm run build", | ||
@@ -22,3 +23,3 @@ "test": "jest --verbose --passWithNoTests", | ||
}, | ||
"license": "GPL-3.0", | ||
"license": "AGPL-3.0", | ||
"jest": { | ||
@@ -38,2 +39,3 @@ "preset": "ts-jest/presets/js-with-ts", | ||
"jest": "^26.4.2", | ||
"lockfile-lint": "^4.3.7", | ||
"semistandard": "^14.2.0", | ||
@@ -40,0 +42,0 @@ "ts-jest": "^26.2.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
105993
60
1172
1
9