Event Handling in Loro
Loro implements an event system to track changes in the document. This section explains when events are emitted and how transactions work in Loro.
Event Emission Points
-
Local Operations: For local operations (like insertions or deletions on text), the operations are first placed in a pending state within an internal transaction.
-
Transaction Commit: When a transaction is committed, all pending operations collectively emit their corresponding events. This transaction commit occurs in two scenarios:
- When
LoroDoc.commit()
is explicitly called - Automatically before an import or export operation
- When
-
Remote Import: When importing changes from a remote source using the
import()
method, events are emitted for the imported operations. This allows the local document to react to changes made by other peers.const doc = new Loro(); doc.subscribe((event) => { console.log("Event:", event); }); doc.import(remoteChanges); // This will trigger events for the imported changes
Transaction Behavior
Operations within a transaction are not immediately committed to the internal oplog. They are only committed when the transaction itself is committed. This affects version information:
- Before commit:
version()
,version_vector()
, andfrontiers()
will show version information from before the local operations. - After commit: These methods will reflect the updated version information including the committed operations.
Triggering a Commit
There are several ways to trigger a commit:
-
Explicit Commit: Directly calling the
commit()
method on the Loro document.const doc = new Loro(); const text = doc.getText("myText"); text.insert(0, "Hello, Loro!"); doc.commit(); // This commits pending operations and emits events
-
Before Import/Export: A commit is automatically triggered before executing an import operation.
const doc1 = new Loro(); doc1.setPeerId(1); const doc2 = new Loro(); doc2.setPeerId(2); // Some ops on doc1 and doc2 doc1.getText("text").insert(0, "Alice"); doc2.getText("text").insert(0, "Hello, Loro!"); console.log(doc1.version().toJSON()); // Map(0) {} console.log(doc2.version().toJSON()); // Map(0) {} const updates = doc1.exportFrom(); doc2.import(updates); // This first commits any pending operations in doc2 console.log(doc2.version().toJSON()); // Map(2) { "1" => 5, "2" => 12 } console.log(doc1.version().toJSON()); // Map(2) { "1" => 5 }
Transactions in Loro
It's important to note that Loro's concept of a transaction differs from traditional database transactions:
- Loro transactions do not have ACID properties.
- They primarily serve as event wrappers.
- There is no rollback mechanism if an operation fails.