Immer patches for Array are correct, yet inefficient. Suggesting a new algorithm for optimized patches
Maintainer antworten meist innerhalb von 4 Tagen
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Anfängerfreundlichkeit
- 25/100
- Issue-Typ
- Feature
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Veraltet
- Tech-Stack
- javascript, typescript
- Bereich
- performance
Rechercherichtung
Beginne mit dem Array-Patch-Test in tests/patch.js, insbesondere mit dem Fall "arrays - multiple prepend" in den referenzierten Zeilen. Vergleiche die aktuellen erwarteten Patches mit dem vorgeschlagenen Ergebnis und bewerte anschließend den vorgeschlagenen Algorithmus für begrenztes Matching im Hinblick auf prepend, splice und andere Array-Änderungen. Als erledigt gilt die Aufgabe, wenn das optimierte Verhalten weiterhin korrekt ist und gleichzeitig unnötige Patches bei kleinen Array-Änderungen reduziert werden.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
I am thinking as offering it as a pull request - let me know what you think
🚀 Feature Proposal
Today when computing a patch on arrays, immer compares objects by index, which results in all array change in case of unshift or splice usage. An example is the following test taken from immer testing -
https://github.com/immerjs/immer/blob/main/__tests__/patch.js#L543-L559
describe("arrays - multiple prepend", () => {
runPatchTest(
{x: [1, 2, 3]},
d => {
d.x.unshift(4)
d.x.unshift(5)
// 4,5,1,2,3
},
[
{op: "replace", path: ["x", 0], value: 5},
{op: "replace", path: ["x", 1], value: 4},
{op: "replace", path: ["x", 2], value: 1},
{op: "add", path: ["x", 3], value: 2},
{op: "add", path: ["x", 4], value: 3}
]
)
})
the expected result should be instead
[
{op: "add", path: ["x", 0], value: 5},
{op: "add", path: ["x", 1], value: 4}
]
Motivation
I am working on a new framework that also serializes patches, and the above is a performance issue.
Consider the above case - for an array of object, lets say an array of 100 objects with 10 attributes each, the current algorithm will generate 1000 patches, while my suggestion is to produce only 1 per added / removed object
Can this be solved in user-land code?
no
Example
See the example above.
Usage: immer -> serialize -> deserialize -> patched object
suggested algorithm
(pseudo code)
the problem with json diff is that given two arrays, without any additional knowledge, to figure out if an item was
pushed to the front, we have to do a === comparison between the array items, which is O(n^2) complexity.
for (let a = 0; a < A.length; a++) {
for (let b = 0; b < A.length; b++) {
if (A[a] === B[b])
// compute the diff
}
}
However, we can create an algorithm focused on small changes that has complexity O(n) with a cutoff.
The algorithm makes the assumption that small changes can be found fast and require small number of mutations to describe.
The cutoff is set at let limit = log(min(A.length, B.length)) and the algorithm has complexity O(limit^2) ~ O(n)
The algorithm -
let limit = log(min(A.length, B.length));
let a=0, b=0;
mainLoop: while (a < A.length && b < B.length) {
if (A(a) === B(b)) {
a += 1;
b += 1
}
continue;
for (let seekSize = 1; seekSize < limit; seekSize++) {
for (let index = 1; index <= seekSize; index++) {
if (A[a+index] === B[b+seekSize-index])
// we have a match, the elements from A between (a..a+index) and replace them with the items from B between (b..b+seekSize-index)
continue mainLoop;
}
}
// revert to direct comparison of attributes json diff model (the standard model used by all other algorithms)
}
- Vorherrschende Sprache
- JavaScript
- Sterne
- 29k
- Forks
- 905
- Ø Merge
- 3 T. 16 Std.
- Gemergte PRs (30 T.)
- 22
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus immerjs/immer
-
Shrinking an array with `length =` and growing it back loses the patches for the truncated indicesEvtl. vergeben @RClaudiuM hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 75/100
Maintainer antworten meist innerhalb von 4 Tagen
-
Schwierigkeit 3/5 1-2 Tage Anfängerfreundlichkeit 35/100
Maintainer antworten meist innerhalb von 4 Tagen
-
Docs: Chinese (zh-CN) website translation is outdated vs English docsEvtl. wieder frei @lijiayou0728 hat das vor 91 Tagen übernommen, und es ist kein Pull Request offen. Offen
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 55/100
immerjs/immer#1242 · 5 Kommentare ·
Maintainer antworten meist innerhalb von 4 Tagen
-
question
Schwierigkeit 5/5 Über eine Woche Anfängerfreundlichkeit 35/100
Maintainer antworten meist innerhalb von 4 Tagen
-
Schwierigkeit 5/5 Über eine Woche Anfängerfreundlichkeit 35/100
immerjs/immer#1217 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 4 Tagen
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
Automattic/node-canvas#2633 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
capricorn86/happy-dom#2594 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 79/100
microsoft/monaco-editor#5575 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
Maintainer antworten meist innerhalb von 1 Tag