Docs
Tutorial
Event Handling

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

  1. Local Operations: For local operations (like insertions or deletions on text), the operations are first placed in a pending state within an internal transaction.

  2. 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
  3. 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(), and frontiers() 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:

  1. 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
  2. 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.