From fe48efe64f07b9d98aecc63c2234230d2fb1a76a Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Thu, 9 Mar 2023 13:44:52 +0100 Subject: [PATCH] fix generating too many cleanup transactions. closes #506 --- src/types/YXmlFragment.js | 3 ++- src/utils/Transaction.js | 11 +++++++++-- tests/doc.tests.js | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/types/YXmlFragment.js b/src/types/YXmlFragment.js index b229a4ac..06b1c0de 100644 --- a/src/types/YXmlFragment.js +++ b/src/types/YXmlFragment.js @@ -257,7 +257,8 @@ export class YXmlFragment extends AbstractType { * @return {string} The string representation of all children. */ toString () { - return typeListMap(this, xml => xml.toString()).join('') + // toString can result in many cleanup transactions. We wrap all cleanup transactions here to reduce the work + return transact(/** @type {Doc} */ (this.doc), () => typeListMap(this, xml => xml.toString()).join('')) } /** diff --git a/src/utils/Transaction.js b/src/utils/Transaction.js index f6a1179a..1e553a90 100644 --- a/src/utils/Transaction.js +++ b/src/utils/Transaction.js @@ -376,15 +376,21 @@ const cleanupTransactions = (transactionCleanups, i) => { /** * Implements the functionality of `y.transact(()=>{..})` * + * @template T * @param {Doc} doc - * @param {function(Transaction):void} f + * @param {function(Transaction):T} f * @param {any} [origin=true] + * @return {T} * * @function */ export const transact = (doc, f, origin = null, local = true) => { const transactionCleanups = doc._transactionCleanups let initialCall = false + /** + * @type {any} + */ + let result = null if (doc._transaction === null) { initialCall = true doc._transaction = new Transaction(doc, origin, local) @@ -395,7 +401,7 @@ export const transact = (doc, f, origin = null, local = true) => { doc.emit('beforeTransaction', [doc._transaction, doc]) } try { - f(doc._transaction) + result = f(doc._transaction) } finally { if (initialCall) { const finishCleanup = doc._transaction === transactionCleanups[0] @@ -413,4 +419,5 @@ export const transact = (doc, f, origin = null, local = true) => { } } } + return result } diff --git a/tests/doc.tests.js b/tests/doc.tests.js index c6211977..e2910a1f 100644 --- a/tests/doc.tests.js +++ b/tests/doc.tests.js @@ -2,6 +2,24 @@ import * as Y from '../src/index.js' import * as t from 'lib0/testing' +/** + * @param {t.TestCase} _tc + */ +export const testAfterTransactionRecursion = _tc => { + const ydoc = new Y.Doc() + const yxml = ydoc.getXmlFragment('') + ydoc.on('afterTransaction', tr => { + if (tr.origin === 'test') { + yxml.toJSON() + } + }) + ydoc.transact(_tr => { + for (let i = 0; i < 15000; i++) { + yxml.push([new Y.XmlText('a')]) + } + }, 'test') +} + /** * @param {t.TestCase} _tc */