mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 21:07:43 +00:00
refactor: call events subs without await now
This commit is contained in:
parent
88003bdffe
commit
6860132ada
4 changed files with 78 additions and 71 deletions
|
@ -118,12 +118,19 @@ impl Loro {
|
|||
Self(RefCell::new(LoroDoc::new()))
|
||||
}
|
||||
|
||||
pub fn txn(&self) -> Transaction {
|
||||
Transaction(self.0.borrow().txn().unwrap())
|
||||
}
|
||||
|
||||
pub fn txn_with_origin(&self, origin: &str) -> Transaction {
|
||||
Transaction(self.0.borrow().txn_with_origin(origin).unwrap())
|
||||
/// Create a new Loro transaction.
|
||||
/// There can be only one transaction at a time.
|
||||
///
|
||||
/// It's caller's responsibility to call `commit` or `abort` on the transaction.
|
||||
/// Transaction.free() will commit the transaction if it's not committed or aborted.
|
||||
#[wasm_bindgen(js_name = "newTransaction")]
|
||||
pub fn new_transaction(&self, origin: Option<String>) -> Transaction {
|
||||
Transaction(Some(
|
||||
self.0
|
||||
.borrow()
|
||||
.txn_with_origin(&origin.unwrap_or_default())
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = "clientId", method, getter)]
|
||||
|
@ -247,7 +254,7 @@ impl Loro {
|
|||
self.0
|
||||
.borrow_mut()
|
||||
.subscribe_deep(Arc::new(move |e| {
|
||||
call_after_micro_task(observer.clone(), e);
|
||||
call_subscriber(observer.clone(), e);
|
||||
}))
|
||||
.into_u32()
|
||||
}
|
||||
|
@ -268,25 +275,43 @@ impl Loro {
|
|||
let origin = origin.as_string().unwrap();
|
||||
debug_log::group!("transaction with origin: {}", origin);
|
||||
let txn = self.0.borrow().txn_with_origin(&origin)?;
|
||||
let js_txn = JsValue::from(Transaction(txn));
|
||||
let js_txn = JsValue::from(Transaction(Some(txn)));
|
||||
let ans = f.call1(&JsValue::NULL, &js_txn);
|
||||
debug_log::group_end!();
|
||||
ans
|
||||
}
|
||||
}
|
||||
|
||||
fn call_after_micro_task(ob: observer::Observer, e: DiffEvent) {
|
||||
let promise = Promise::resolve(&JsValue::NULL);
|
||||
type C = Closure<dyn FnMut(JsValue)>;
|
||||
let drop_handler: Rc<RefCell<Option<C>>> = Rc::new(RefCell::new(None));
|
||||
let copy = drop_handler.clone();
|
||||
fn call_subscriber(ob: observer::Observer, e: DiffEvent) {
|
||||
let event = Event {
|
||||
from_children: e.from_children,
|
||||
local: e.doc.local,
|
||||
origin: e.doc.origin.to_string(),
|
||||
target: e.container.id.clone(),
|
||||
diff: Either::A(e.container.diff.to_owned()),
|
||||
path: Either::A(e.container.path.iter().map(|x| x.1.clone()).collect()),
|
||||
};
|
||||
|
||||
if let Err(e) = ob.call1(&event.into()) {
|
||||
console_error!("Error when calling observer: {:#?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn call_after_micro_task(ob: observer::Observer, e: DiffEvent) {
|
||||
let promise = Promise::resolve(&JsValue::NULL);
|
||||
type C = Closure<dyn FnMut(JsValue)>;
|
||||
let drop_handler: Rc<RefCell<Option<C>>> = Rc::new(RefCell::new(None));
|
||||
let copy = drop_handler.clone();
|
||||
let event = Event {
|
||||
from_children: e.from_children,
|
||||
local: e.doc.local,
|
||||
origin: e.doc.origin.to_string(),
|
||||
target: e.container.id.clone(),
|
||||
diff: Either::A(e.container.diff.to_owned()),
|
||||
path: Either::A(e.container.path.iter().map(|x| x.1.clone()).collect()),
|
||||
};
|
||||
|
||||
let closure = Closure::once(move |_: JsValue| {
|
||||
let ans = ob.call1(&event.into());
|
||||
drop(copy);
|
||||
|
@ -294,6 +319,7 @@ fn call_after_micro_task(ob: observer::Observer, e: DiffEvent) {
|
|||
console_error!("Error when calling observer: {:#?}", e);
|
||||
}
|
||||
});
|
||||
|
||||
let _ = promise.then(&closure);
|
||||
drop_handler.borrow_mut().replace(closure);
|
||||
}
|
||||
|
@ -312,6 +338,7 @@ enum Either<A, B> {
|
|||
#[wasm_bindgen]
|
||||
pub struct Event {
|
||||
pub local: bool,
|
||||
pub from_children: bool,
|
||||
origin: String,
|
||||
target: ContainerID,
|
||||
diff: Either<Diff, JsValue>,
|
||||
|
@ -360,14 +387,29 @@ impl Event {
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Transaction(Txn);
|
||||
pub struct Transaction(Option<Txn>);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Transaction {
|
||||
pub fn commit(self) -> JsResult<()> {
|
||||
self.0.commit()?;
|
||||
pub fn commit(&mut self) -> JsResult<()> {
|
||||
if let Some(x) = self.0.take() {
|
||||
x.commit()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn abort(&mut self) -> JsResult<()> {
|
||||
if let Some(x) = self.0.take() {
|
||||
x.abort();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_mut(&mut self) -> JsResult<&mut Txn> {
|
||||
self.0
|
||||
.as_mut()
|
||||
.ok_or_else(|| JsValue::from_str("Transaction is aborted"))
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
@ -381,7 +423,7 @@ impl LoroText {
|
|||
index: usize,
|
||||
content: &str,
|
||||
) -> JsResult<()> {
|
||||
self.0.insert_utf16(&mut txn.0, index, content)?;
|
||||
self.0.insert_utf16(txn.as_mut()?, index, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -391,7 +433,7 @@ impl LoroText {
|
|||
index: usize,
|
||||
len: usize,
|
||||
) -> JsResult<()> {
|
||||
self.0.delete_utf16(&mut txn.0, index, len)?;
|
||||
self.0.delete_utf16(txn.as_mut()?, index, len)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -417,7 +459,7 @@ impl LoroText {
|
|||
let ans = loro.0.borrow_mut().subscribe(
|
||||
&self.0.id(),
|
||||
Arc::new(move |e| {
|
||||
call_after_micro_task(observer.clone(), e);
|
||||
call_subscriber(observer.clone(), e);
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -444,12 +486,12 @@ impl LoroMap {
|
|||
key: &str,
|
||||
value: JsValue,
|
||||
) -> JsResult<()> {
|
||||
self.0.insert(&mut txn.0, key, value.into())?;
|
||||
self.0.insert(txn.as_mut()?, key, value.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn __txn_delete(&mut self, txn: &mut Transaction, key: &str) -> JsResult<()> {
|
||||
self.0.delete(&mut txn.0, key)?;
|
||||
self.0.delete(txn.as_mut()?, key)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -487,12 +529,13 @@ impl LoroMap {
|
|||
"list" | "List" => ContainerType::List,
|
||||
_ => return Err(JsValue::from_str(CONTAINER_TYPE_ERR)),
|
||||
};
|
||||
let idx = self.0.insert_container(&mut txn.0, key, type_)?;
|
||||
let t = txn.as_mut()?;
|
||||
let idx = self.0.insert_container(t, key, type_)?;
|
||||
|
||||
let container = match type_ {
|
||||
ContainerType::Text => LoroText(txn.0.get_text(idx)).into(),
|
||||
ContainerType::Map => LoroMap(txn.0.get_map(idx)).into(),
|
||||
ContainerType::List => LoroList(txn.0.get_list(idx)).into(),
|
||||
ContainerType::Text => LoroText(t.get_text(idx)).into(),
|
||||
ContainerType::Map => LoroMap(t.get_map(idx)).into(),
|
||||
ContainerType::List => LoroList(t.get_list(idx)).into(),
|
||||
};
|
||||
Ok(container)
|
||||
}
|
||||
|
@ -502,7 +545,7 @@ impl LoroMap {
|
|||
let id = loro.0.borrow_mut().subscribe(
|
||||
&self.0.id(),
|
||||
Arc::new(move |e| {
|
||||
call_after_micro_task(observer.clone(), e);
|
||||
call_subscriber(observer.clone(), e);
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -526,7 +569,7 @@ impl LoroList {
|
|||
index: usize,
|
||||
value: JsValue,
|
||||
) -> JsResult<()> {
|
||||
self.0.insert(&mut txn.0, index, value.into())?;
|
||||
self.0.insert(txn.as_mut()?, index, value.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -536,7 +579,7 @@ impl LoroList {
|
|||
index: usize,
|
||||
len: usize,
|
||||
) -> JsResult<()> {
|
||||
self.0.delete(&mut txn.0, index, len)?;
|
||||
self.0.delete(txn.as_mut()?, index, len)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -574,11 +617,12 @@ impl LoroList {
|
|||
"list" | "List" => ContainerType::List,
|
||||
_ => return Err(JsValue::from_str(CONTAINER_TYPE_ERR)),
|
||||
};
|
||||
let idx = self.0.insert_container(&mut txn.0, pos, _type)?;
|
||||
let t = txn.as_mut()?;
|
||||
let idx = self.0.insert_container(t, pos, _type)?;
|
||||
let container = match _type {
|
||||
ContainerType::Text => LoroText(txn.0.get_text(idx)).into(),
|
||||
ContainerType::Map => LoroMap(txn.0.get_map(idx)).into(),
|
||||
ContainerType::List => LoroList(txn.0.get_list(idx)).into(),
|
||||
ContainerType::Text => LoroText(t.get_text(idx)).into(),
|
||||
ContainerType::Map => LoroMap(t.get_map(idx)).into(),
|
||||
ContainerType::List => LoroList(t.get_list(idx)).into(),
|
||||
};
|
||||
Ok(container)
|
||||
}
|
||||
|
@ -588,7 +632,7 @@ impl LoroList {
|
|||
let ans = loro.0.borrow_mut().subscribe(
|
||||
&self.0.id(),
|
||||
Arc::new(move |e| {
|
||||
call_after_micro_task(observer.clone(), e);
|
||||
call_subscriber(observer.clone(), e);
|
||||
}),
|
||||
);
|
||||
Ok(ans.into_u32())
|
||||
|
|
|
@ -22,7 +22,6 @@ describe("event", () => {
|
|||
loro.transact((tx) => {
|
||||
text.insert(tx, 0, "123");
|
||||
});
|
||||
await zeroMs();
|
||||
expect(lastEvent?.target).toEqual(id);
|
||||
});
|
||||
|
||||
|
@ -39,7 +38,6 @@ describe("event", () => {
|
|||
return subMap;
|
||||
});
|
||||
|
||||
await zeroMs();
|
||||
expect(lastEvent?.path).toStrictEqual(["map", "sub"]);
|
||||
const text = loro.transact((tx) => {
|
||||
const list = subMap.insertContainer(tx, "list", "List");
|
||||
|
@ -47,11 +45,9 @@ describe("event", () => {
|
|||
const text = list.insertContainer(tx, 1, "Text");
|
||||
return text;
|
||||
});
|
||||
await zeroMs();
|
||||
loro.transact((tx) => {
|
||||
text.insert(tx, 0, "3");
|
||||
});
|
||||
await zeroMs();
|
||||
expect(lastEvent?.path).toStrictEqual(["map", "sub", "list", 1]);
|
||||
});
|
||||
|
||||
|
@ -65,14 +61,12 @@ describe("event", () => {
|
|||
loro.transact(tx => {
|
||||
text.insert(tx, 0, "3");
|
||||
})
|
||||
await zeroMs();
|
||||
expect(lastEvent?.diff).toStrictEqual(
|
||||
{ type: "text", diff: [{ type: "insert", value: "3" }] } as TextDiff,
|
||||
);
|
||||
loro.transact(tx => {
|
||||
text.insert(tx, 1, "12");
|
||||
})
|
||||
await zeroMs();
|
||||
expect(lastEvent?.diff).toStrictEqual(
|
||||
{
|
||||
type: "text",
|
||||
|
@ -91,14 +85,12 @@ describe("event", () => {
|
|||
loro.transact(tx => {
|
||||
text.insert(tx, 0, "3");
|
||||
})
|
||||
await zeroMs();
|
||||
expect(lastEvent?.diff).toStrictEqual(
|
||||
{ type: "list", diff: [{ type: "insert", value: ["3"] }] } as ListDiff,
|
||||
);
|
||||
loro.transact(tx => {
|
||||
text.insert(tx, 1, "12");
|
||||
})
|
||||
await zeroMs();
|
||||
expect(lastEvent?.diff).toStrictEqual(
|
||||
{
|
||||
type: "list",
|
||||
|
@ -118,7 +110,6 @@ describe("event", () => {
|
|||
map.set(tx, "0", "3");
|
||||
map.set(tx, "1", "2");
|
||||
});
|
||||
await zeroMs();
|
||||
expect(lastEvent?.diff).toStrictEqual(
|
||||
{
|
||||
type: "map",
|
||||
|
@ -132,7 +123,6 @@ describe("event", () => {
|
|||
map.set(tx, "0", "0");
|
||||
map.set(tx, "1", "1");
|
||||
});
|
||||
await zeroMs();
|
||||
expect(lastEvent?.diff).toStrictEqual(
|
||||
{
|
||||
type: "map",
|
||||
|
@ -165,7 +155,6 @@ describe("event", () => {
|
|||
loro.transact(tx => {
|
||||
text.insert(tx, 1, "456");
|
||||
});
|
||||
await zeroMs();
|
||||
expect(ran).toBeTruthy();
|
||||
// subscribeOnce test
|
||||
expect(text.toString()).toEqual("145623");
|
||||
|
@ -192,19 +181,15 @@ describe("event", () => {
|
|||
loro.transact(tx =>
|
||||
map.insertContainer(tx, "sub", "Map")
|
||||
);
|
||||
await zeroMs();
|
||||
expect(times).toBe(1);
|
||||
const text = loro.transact(tx => subMap.insertContainer(tx, "k", "Text"));
|
||||
await zeroMs();
|
||||
expect(times).toBe(2);
|
||||
loro.transact(tx => text.insert(tx, 0, "123"));
|
||||
await zeroMs();
|
||||
expect(times).toBe(3);
|
||||
|
||||
// unsubscribe
|
||||
loro.unsubscribe(sub);
|
||||
loro.transact(tx => text.insert(tx, 0, "123"));
|
||||
await zeroMs();
|
||||
expect(times).toBe(3);
|
||||
});
|
||||
|
||||
|
@ -217,16 +202,13 @@ describe("event", () => {
|
|||
});
|
||||
|
||||
const text = loro.transact(tx => list.insertContainer(tx, 0, "Text"));
|
||||
await zeroMs();
|
||||
expect(times).toBe(1);
|
||||
loro.transact(tx => text.insert(tx, 0, "123"));
|
||||
await zeroMs();
|
||||
expect(times).toBe(2);
|
||||
|
||||
// unsubscribe
|
||||
loro.unsubscribe(sub);
|
||||
loro.transact(tx => text.insert(tx, 0, "123"));
|
||||
await zeroMs();
|
||||
expect(times).toBe(2);
|
||||
});
|
||||
});
|
||||
|
@ -257,19 +239,15 @@ describe("event", () => {
|
|||
}
|
||||
});
|
||||
loro.transact(tx => text.insert(tx, 0, "你好"));
|
||||
await zeroMs();
|
||||
expect(text.toString()).toBe(string);
|
||||
|
||||
loro.transact(tx => text.insert(tx, 1, "世界"));
|
||||
await zeroMs();
|
||||
expect(text.toString()).toBe(string);
|
||||
|
||||
loro.transact(tx => text.insert(tx, 2, "👍"));
|
||||
await zeroMs();
|
||||
expect(text.toString()).toBe(string);
|
||||
|
||||
loro.transact(tx => text.insert(tx, 2, "♪(^∇^*)"));
|
||||
await zeroMs();
|
||||
expect(text.toString()).toBe(string);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ describe("Frontiers", () => {
|
|||
it("two clients", () => {
|
||||
const doc = new Loro();
|
||||
const text = doc.getText("text");
|
||||
const txn = doc.txn();
|
||||
const txn = doc.newTransaction("");
|
||||
text.insert(txn, 0, "0");
|
||||
txn.commit();
|
||||
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import { assertType, describe, expect, it } from "vitest";
|
||||
import {
|
||||
Delta,
|
||||
ListDiff,
|
||||
Loro,
|
||||
LoroEvent,
|
||||
LoroList,
|
||||
LoroMap,
|
||||
MapDiff as MapDiff,
|
||||
PrelimList,
|
||||
PrelimMap,
|
||||
PrelimText,
|
||||
TextDiff,
|
||||
Transaction,
|
||||
} from "../src";
|
||||
import { expectTypeOf } from "vitest";
|
||||
|
@ -35,7 +30,6 @@ describe("transaction", () => {
|
|||
text.insert(txn, 0, "hello world");
|
||||
assertEquals(count, 0);
|
||||
});
|
||||
await one_ms();
|
||||
assertEquals(count, 1);
|
||||
});
|
||||
|
||||
|
@ -55,7 +49,6 @@ describe("transaction", () => {
|
|||
text.insert(txn, 0, "hello world");
|
||||
assertEquals(count, 0);
|
||||
}, "origin");
|
||||
await one_ms();
|
||||
assertEquals(count, 1);
|
||||
});
|
||||
});
|
||||
|
@ -81,18 +74,15 @@ describe("subscribe", () => {
|
|||
text.insert(txn, 0, "hello world");
|
||||
})
|
||||
|
||||
await one_ms();
|
||||
assertEquals(count, 2);
|
||||
loro.transact((txn) => {
|
||||
text.insert(txn, 0, "hello world");
|
||||
});
|
||||
await one_ms();
|
||||
assertEquals(count, 3);
|
||||
loro.unsubscribe(sub);
|
||||
loro.transact(txn => {
|
||||
text.insert(txn, 0, "hello world");
|
||||
})
|
||||
await one_ms();
|
||||
assertEquals(count, 3);
|
||||
});
|
||||
|
||||
|
@ -109,7 +99,6 @@ describe("subscribe", () => {
|
|||
text.insert(txn, 0, "hello world");
|
||||
})
|
||||
|
||||
await one_ms();
|
||||
assertEquals(count, 1);
|
||||
loro.transact(txn => {
|
||||
text.insert(txn, 0, "hello world");
|
||||
|
@ -128,18 +117,15 @@ describe("subscribe", () => {
|
|||
loro.transact(loro => {
|
||||
text.insert(loro, 0, "hello world");
|
||||
})
|
||||
await one_ms();
|
||||
assertEquals(count, 1);
|
||||
loro.transact(loro => {
|
||||
text.insert(loro, 0, "hello world");
|
||||
})
|
||||
await one_ms();
|
||||
assertEquals(count, 2);
|
||||
loro.unsubscribe(sub);
|
||||
loro.transact(loro => {
|
||||
text.insert(loro, 0, "hello world");
|
||||
})
|
||||
await one_ms();
|
||||
assertEquals(count, 2);
|
||||
});
|
||||
});
|
||||
|
@ -170,7 +156,6 @@ describe("sync", () => {
|
|||
aText.insert(txn, 0, "abc");
|
||||
});
|
||||
|
||||
await one_ms();
|
||||
assertEquals(aText.toString(), bText.toString());
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue