Promise.PSD
Dexie.Promise.PSD is a custom Async Context to maintain ongoing database transactions. Unlike other zone implementations, Dexie’s zones are unobtrusive, meaning that the zone system does not require including any monkey-patching script or import. Dexie is not dependant on zone.js or any other zone implementation.
As of Dexie 2.0.0, this system is also capable of maintaining contexts between await expressions (both transpiled and browser-native. The zone system has been tested agains native await with Chrome 55+, Edge 14+, Firefox, Opera and Safari. Transpiled support has been tested with babel and typescript).
Syntax
// Create a PSD scope
Dexie.Promise.newPSD (function () {
// Put something in it.
Dexie.Promise.PSD.promiseSpecificVariable = 3;
// Create a promise that uses it
new Dexie.Promise(function (resolve, reject) {
setTimeout(resolve, 1000);
}).then (function () {
// This callback will get same PSD instance as was active when .then() was called
assert (Dexie.Promise.PSD.promiseSpecificVariable == 3);
});
});
Description
Analogous to Thread-specific data, Promise-specific data contains static data bound to the execution flow of a Promise flow or tree.
Purpose
In the threading world, Thread-specific data can be used to hold a state on the currently executing thread. Authorization Engines often use thread-specific data to hold the current authenticated principal instead of having to pass that object around, which makes authorization more reliable, logging frameworks also rely on thread-specific content so that current username can be invoked in each log entry without a component needing to know about that when calling .log(). Reentrant mutexes / recursive locking is another important pattern that enables one function to lock a mutex, then call other sub functions that also locks the same mutex without a deadlock arising. PSD makes that pattern possible in the “Promise land”…
In Dexie, PSD is used for:
- Maintaining transaction scopes
- Enabling reentrant write-locks on transactions
- Enabling subscribers to db.on(‘ready’) work on db before db.open() completes
Difference Between Thread-specific data and PSD
Thread-specific Data is one-dimensional. You can set Thread-static property that will be set for the currently running thread. PSD is a tree (or stack on most cases) where each new PSD acts as a stack frame that will derive from its parent. This makes PSD data automatically disappear when a Promise.newPSD() goes out of scope. This is also necessary since Promise chains (unlike threads) can all root down the the same promise but be forked on certain frames.
Difference from Angular’s Zone.js
Dexie’s zone system is unobtrusive, meaning that it does not require your application to include a monkey-patching script at the top of the HTML page. Dexie’s zone system only maintains contexts between promises and does not propagate contexts into other async apis, such as setTimeout() etc.
Non-Standard
PSD is Dexie-proprietary invention and is not standardized in any Promise specification. We’ll be following the TC39 AsyncContext proposal closely and gradually adapt the API to align with the specification.
How To Use
Dexie.Promise.newPSD(function() {
// In this function, we have a Dexie.Promise.PSD to work with.
Dexie.Promise.PSD.myVar = 3;
new Dexie.Promise(function(resolve, reject){
// Promise constructor will derive from current scope:
alert (Dexie.Promise.PSD.myVar); // Will alert "3"
// Let's resolve the promise to explain the then() method:
setTimeout(resolve, 100);
}).then (function(){
// Here, we have the same PSD as when Promise instance was created
alert (Dexie.Promise.PSD.myVar); // Will alert "3"
}).catch (function() {
alert (Dexie.Promise.PSD.myVar); // Would alert "3" as well
});
});
alert (Dexie.Promise.PSD);
// Will alert "null" (unless code was called from other Promise)
Sub Scopes
In case calling Dexie.Promise.newPSD() when already in a PSD scope (Dexie.Promise.PSD !== null), the new PSD will derive prototypically from the outer PSD scope.
//
// top-level: Dexie.Promise.PSD === null
//
Dexie.Promise.newPSD(function() {
//
// Root-scope:
//
// Play with PSD:
Dexie.Promise.PSD.myVar = 3;
alert (Dexie.Promise.PSD.myVar); // Will alert ("3") (obviously)
Dexie.Promise.newPSD(function() {
//
// Sub-scope: Current PSD derives from parent PSD.
//
// Play with PSD: Override myVar but dont change parent value:
Dexie.Promise.PSD.myOtherVar = 18;
alert (Dexie.Promise.PSD.myVar); // Will alert ("3") (derived value)
alert (Dexie.Promise.PSD.myOtherVar); // Will alert ("18") (direct val)
});
// Back to root scope:
alert (Dexie.Promise.PSD.myOtherVar); // Will alert ("null")
alert (Dexie.Promise.PSD.myVar); // Will alert ("3")
});
// At this point, Dexie.Promise.PSD === null again.
Table of Contents
- API Reference
- Access Control in Dexie Cloud
- Authentication in Dexie Cloud
- Best Practices
- Building Addons
- Collection
- Collection.and()
- Collection.clone()
- Collection.count()
- Collection.delete()
- Collection.desc()
- Collection.distinct()
- Collection.each()
- Collection.eachKey()
- Collection.eachPrimaryKey()
- Collection.eachUniqueKey()
- Collection.filter()
- Collection.first()
- Collection.keys()
- Collection.last()
- Collection.limit()
- Collection.modify()
- Collection.offset()
- Collection.or()
- Collection.primaryKeys()
- Collection.raw()
- Collection.reverse()
- Collection.sortBy()
- Collection.toArray()
- Collection.uniqueKeys()
- Collection.until()
- Compound Index
- Consistency in Dexie Cloud
- Consuming Dexie as a module
- DBCore
- DBCoreAddRequest
- DBCoreCountRequest
- DBCoreCursor
- DBCoreDeleteRangeRequest
- DBCoreDeleteRequest
- DBCoreGetManyRequest
- DBCoreGetRequest
- DBCoreIndex
- DBCoreKeyRange
- DBCoreMutateRequest
- DBCoreMutateResponse
- DBCoreOpenCursorRequest
- DBCorePutRequest
- DBCoreQuery
- DBCoreQueryRequest
- DBCoreQueryResponse
- DBCoreRangeType
- DBCoreSchema
- DBCoreTable
- DBCoreTableSchema
- DBCoreTransaction
- DBCoreTransactionMode
- DBPermissionSet
- Deprecations
- Derived Work
- Design
- Dexie Cloud CLI
- Dexie Cloud Docs
- Dexie Cloud REST API
- Dexie Constructor
- Dexie.AbortError
- Dexie.BulkError
- Dexie.ConstraintError
- Dexie.DataCloneError
- Dexie.DataError
- Dexie.DatabaseClosedError
- Dexie.IncompatiblePromiseError
- Dexie.InternalError
- Dexie.InvalidAccessError
- Dexie.InvalidArgumentError
- Dexie.InvalidStateError
- Dexie.InvalidTableError
- Dexie.MissingAPIError
- Dexie.ModifyError
- Dexie.NoSuchDatabaseErrorError
- Dexie.NotFoundError
- Dexie.Observable
- Dexie.Observable.DatabaseChange
- Dexie.OpenFailedError
- Dexie.PrematureCommitError
- Dexie.QuotaExceededError
- Dexie.ReadOnlyError
- Dexie.SchemaError
- Dexie.SubTransactionError
- Dexie.Syncable
- Dexie.Syncable.IDatabaseChange
- Dexie.Syncable.IPersistentContext
- Dexie.Syncable.ISyncProtocol
- Dexie.Syncable.StatusTexts
- Dexie.Syncable.Statuses
- Dexie.Syncable.registerSyncProtocol()
- Dexie.TimeoutError
- Dexie.TransactionInactiveError
- Dexie.UnknownError
- Dexie.UnsupportedError
- Dexie.UpgradeError()
- Dexie.VersionChangeError
- Dexie.VersionError
- Dexie.[table]
- Dexie.addons
- Dexie.async()
- Dexie.backendDB()
- Dexie.close()
- Dexie.currentTransaction
- Dexie.debug
- Dexie.deepClone()
- Dexie.defineClass()
- Dexie.delByKeyPath()
- Dexie.delete()
- Dexie.derive()
- Dexie.events()
- Dexie.exists()
- Dexie.extend()
- Dexie.fakeAutoComplete()
- Dexie.getByKeyPath()
- Dexie.getDatabaseNames()
- Dexie.hasFailed()
- Dexie.ignoreTransaction()
- Dexie.isOpen()
- Dexie.js
- Dexie.name
- Dexie.on()
- Dexie.on.blocked
- Dexie.on.close
- Dexie.on.error
- Dexie.on.populate
- Dexie.on.populate-(old-version)
- Dexie.on.ready
- Dexie.on.storagemutated
- Dexie.on.versionchange
- Dexie.open()
- Dexie.override()
- Dexie.semVer
- Dexie.setByKeyPath()
- Dexie.shallowClone()
- Dexie.spawn()
- Dexie.table()
- Dexie.tables
- Dexie.transaction()
- Dexie.transaction()-(old-version)
- Dexie.use()
- Dexie.verno
- Dexie.version
- Dexie.version()
- Dexie.vip()
- Dexie.waitFor()
- DexieCloudOptions
- DexieError
- Docs Home
- Download
- Export and Import Database
- Get started with Dexie in Angular
- Get started with Dexie in React
- Get started with Dexie in Svelte
- Get started with Dexie in Vue
- Hello World
- How To Use the StorageManager API
- Inbound
- IndexSpec
- Indexable Type
- IndexedDB on Safari
- Invite
- Migrating existing DB to Dexie
- MultiEntry Index
- Promise
- Promise.PSD
- Promise.catch()
- Promise.finally()
- Promise.on.error
- Promise.onuncatched
- Purchase Subscription
- Questions and Answers
- Releasing Dexie
- Road Map
- Road Map: Dexie 4.0
- Road Map: Dexie Cloud
- Run Dexie Cloud on Own Servers
- Sharding and Scalability
- Simplify with yield
- Stop Putin!
- SyncState
- Table
- Table Schema
- Table.add()
- Table.bulkAdd()
- Table.bulkDelete()
- Table.bulkGet()
- Table.bulkPut()
- Table.bulkUpdate()
- Table.clear()
- Table.count()
- Table.defineClass()
- Table.delete()
- Table.each()
- Table.filter()
- Table.get()
- Table.hook('creating')
- Table.hook('deleting')
- Table.hook('reading')
- Table.hook('updating')
- Table.limit()
- Table.mapToClass()
- Table.name
- Table.offset()
- Table.orderBy()
- Table.put()
- Table.reverse()
- Table.schema
- Table.toArray()
- Table.toCollection()
- Table.update()
- Table.where()
- The main limitations of IndexedDB
- Transaction
- Transaction.abort()
- Transaction.on.abort
- Transaction.on.complete
- Transaction.on.error
- Transaction.table()
- Tutorial
- Typescript
- Understanding the basics
- UserLogin
- Version
- Version.stores()
- Version.upgrade()
- WhereClause
- WhereClause.above()
- WhereClause.aboveOrEqual()
- WhereClause.anyOf()
- WhereClause.anyOfIgnoreCase()
- WhereClause.below()
- WhereClause.belowOrEqual()
- WhereClause.between()
- WhereClause.equals()
- WhereClause.equalsIgnoreCase()
- WhereClause.inAnyRange()
- WhereClause.noneOf()
- WhereClause.notEqual()
- WhereClause.startsWith()
- WhereClause.startsWithAnyOf()
- WhereClause.startsWithAnyOfIgnoreCase()
- WhereClause.startsWithIgnoreCase()
- db.cloud.configure()
- db.cloud.currentUser
- db.cloud.permissions()
- db.syncable.connect()
- db.syncable.delete()
- db.syncable.disconnect()
- db.syncable.getOptions()
- db.syncable.getStatus()
- db.syncable.list()
- db.syncable.on('statusChanged')
- db.syncable.setFilter()
- dexie-cloud-addon
- dexie-react-hooks
- liveQuery()
- unhandledrejection-event
- useLiveQuery()
- useObservable()
- usePermissions()