Skip to content

Commit a2db19e

Browse files
authored
Merge pull request #3792 from tonyraoul/es2023-array-methods
perf: ECMAScript2023 & ECMAScript2022 array methods performance improvement for proxy
2 parents 1a0dd70 + 227290d commit a2db19e

File tree

7 files changed

+161
-4
lines changed

7 files changed

+161
-4
lines changed

.changeset/great-trainers-beg.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"mobx": minor
3+
---
4+
5+
Improve observablearray proxy pefromance for es2023.array and es2022.array methods

.github/workflows/build_and_test.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515
- name: Checkout Repo
1616
uses: actions/checkout@master
1717

18-
- name: Setup Node.js 14.x
18+
- name: Setup Node.js 20.x
1919
uses: actions/setup-node@master
2020
with:
21-
node-version: 14.x
21+
node-version: 20.x
2222

2323
- name: Install Dependencies
2424
run: yarn --frozen-lockfile --ignore-scripts

.github/workflows/coveralls.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
1414
fetch-depth: 0
1515

16-
- name: Setup Node.js 14.x
16+
- name: Setup Node.js 20.x
1717
uses: actions/setup-node@master
1818
with:
19-
node-version: 14.x
19+
node-version: 20.x
2020

2121
- name: Install Dependencies
2222
run: yarn --frozen-lockfile --ignore-scripts

packages/mobx/__tests__/perf/perf.js

+35
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,41 @@ results of this test:
196196
t.end()
197197
})
198198

199+
test(`${version} - array.es2023 findLastIndex methods`, function (t) {
200+
gc()
201+
let aCalc = 0
202+
let bCalc = 0
203+
const ar = observable([0])
204+
const findLastIndexOfZero = computed(function () {
205+
aCalc++
206+
return ar.findLastIndex(x => x === 0);
207+
})
208+
const lastIndexOfZero = computed(function () {
209+
bCalc++
210+
return ar.lastIndexOf(0);
211+
})
212+
mobx.observe(findLastIndexOfZero, voidObserver, true)
213+
mobx.observe(lastIndexOfZero, voidObserver, true)
214+
215+
const start = now()
216+
217+
t.equal(1, aCalc)
218+
t.equal(1, bCalc)
219+
for (let i = 1; i < 10000; i++) ar.push(i)
220+
221+
t.equal(0, lastIndexOfZero.get())
222+
t.equal(0, findLastIndexOfZero.get())
223+
t.equal(10000, aCalc)
224+
t.equal(10000, bCalc)
225+
226+
const end = now()
227+
228+
log(
229+
"Array findLastIndex loop - Updated in " + (end - start) + " ms."
230+
)
231+
t.end()
232+
})
233+
199234
test(`${version} - array reduce`, function (t) {
200235
gc()
201236
let aCalc = 0

packages/mobx/__tests__/v4/base/array.js

+55
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,34 @@ test("find(findIndex) and remove", function () {
154154
expect(a.remove(20)).toBe(false)
155155
})
156156

157+
test("findLast(findLastIndex) and remove", function () {
158+
const a = mobx.observable([10, 20, 20])
159+
let idx = -1
160+
function predicate(item, index) {
161+
if (item === 20) {
162+
idx = index
163+
return true
164+
}
165+
return false
166+
}
167+
;[].findLastIndex;
168+
expect(a.findLast(predicate)).toBe(20)
169+
expect(a.findLastIndex(predicate)).toBe(2)
170+
expect(a.findLast(predicate)).toBe(20)
171+
172+
expect(a.remove(20)).toBe(true)
173+
expect(a.find(predicate)).toBe(20)
174+
expect(idx).toBe(1)
175+
expect(a.findIndex(predicate)).toBe(1)
176+
idx = -1
177+
expect(a.remove(20)).toBe(true)
178+
expect(a.findLast(predicate)).toBe(undefined)
179+
expect(idx).toBe(-1)
180+
expect(a.findLastIndex(predicate)).toBe(-1)
181+
182+
expect(a.remove(20)).toBe(false)
183+
})
184+
157185
test("concat should automatically slice observable arrays, #260", () => {
158186
const a1 = mobx.observable([1, 2])
159187
const a2 = mobx.observable([3, 4])
@@ -587,6 +615,8 @@ test("correct array should be passed to callbacks #2326", () => {
587615
"filter",
588616
"find",
589617
"findIndex",
618+
"findLast",
619+
"findLastIndex",
590620
"flatMap",
591621
"forEach",
592622
"map",
@@ -766,6 +796,31 @@ describe("dehances", () => {
766796
expect([...array.values()]).toEqual([...dehanced.values()])
767797
})
768798

799+
test("toReversed", () => {
800+
expect(array.toReversed()).toEqual(dehanced.toReversed())
801+
})
802+
803+
test("toSorted", () => {
804+
expect(array.toSorted()).toEqual(dehanced.toSorted())
805+
})
806+
807+
test("toSorted with args", () => {
808+
expect(array.toSorted((a, b) => a - b)).toEqual(dehanced.toSorted((a, b) => a - b))
809+
})
810+
811+
test("toSpliced", () => {
812+
expect(array.toSpliced(1, 2)).toEqual(dehanced.toSpliced(1, 2))
813+
})
814+
815+
test("with", () => {
816+
expect(array.with(1, 5)).toEqual(dehanced.with(1, 5))
817+
})
818+
819+
test("at", () => {
820+
expect(array.at(1)).toEqual(dehanced.at(1))
821+
expect(array.at(-1)).toEqual(dehanced.at(-1))
822+
})
823+
769824
test("flat/flatMap", () => {
770825
// not supported in V4
771826
})

packages/mobx/__tests__/v5/base/array.js

+55
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,34 @@ test("find(findIndex) and remove", function () {
178178
expect(a.remove(20)).toBe(false)
179179
})
180180

181+
test("findLast(findLastIndex) and remove", function () {
182+
const a = mobx.observable([10, 20, 20])
183+
let idx = -1
184+
function predicate(item, index) {
185+
if (item === 20) {
186+
idx = index
187+
return true
188+
}
189+
return false
190+
}
191+
;[].findLastIndex;
192+
expect(a.findLast(predicate)).toBe(20)
193+
expect(a.findLastIndex(predicate)).toBe(2)
194+
expect(a.findLast(predicate)).toBe(20)
195+
196+
expect(a.remove(20)).toBe(true)
197+
expect(a.find(predicate)).toBe(20)
198+
expect(idx).toBe(1)
199+
expect(a.findIndex(predicate)).toBe(1)
200+
idx = -1
201+
expect(a.remove(20)).toBe(true)
202+
expect(a.findLast(predicate)).toBe(undefined)
203+
expect(idx).toBe(-1)
204+
expect(a.findLastIndex(predicate)).toBe(-1)
205+
206+
expect(a.remove(20)).toBe(false)
207+
})
208+
181209
test("concat should automatically slice observable arrays, #260", () => {
182210
const a1 = mobx.observable([1, 2])
183211
const a2 = mobx.observable([3, 4])
@@ -630,6 +658,8 @@ test("correct array should be passed to callbacks #2326", () => {
630658
"filter",
631659
"find",
632660
"findIndex",
661+
"findLast",
662+
"findLastIndex",
633663
"flatMap",
634664
"forEach",
635665
"map",
@@ -807,6 +837,31 @@ describe("dehances", () => {
807837
expect([...array.values()]).toEqual([...dehanced.values()])
808838
})
809839

840+
test("toReversed", () => {
841+
expect(array.toReversed()).toEqual(dehanced.toReversed())
842+
})
843+
844+
test("toSorted", () => {
845+
expect(array.toSorted()).toEqual(dehanced.toSorted())
846+
})
847+
848+
test("toSorted with args", () => {
849+
expect(array.toSorted((a, b) => a - b)).toEqual(dehanced.toSorted((a, b) => a - b))
850+
})
851+
852+
test("toSpliced", () => {
853+
expect(array.toSpliced(1, 2)).toEqual(dehanced.toSpliced(1, 2))
854+
})
855+
856+
test("with", () => {
857+
expect(array.with(1, 5)).toEqual(dehanced.with(1, 5))
858+
})
859+
860+
test("at", () => {
861+
expect(array.at(1)).toEqual(dehanced.at(1))
862+
expect(array.at(-1)).toEqual(dehanced.at(-1))
863+
})
864+
810865
test("flat/flatMap", () => {
811866
const nestedArray = [{ value: 1 }, [{ value: 2 }, [{ value: 3 }]]]
812867
const dehancedNestedArray = nestedArray.map(dehancer)

packages/mobx/src/types/observablearray.ts

+7
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ export var arrayExtensions = {
518518
* Without this, everything works as well, but this works
519519
* faster as everything works on unproxied values
520520
*/
521+
addArrayExtension("at", simpleFunc)
521522
addArrayExtension("concat", simpleFunc)
522523
addArrayExtension("flat", simpleFunc)
523524
addArrayExtension("includes", simpleFunc)
@@ -527,15 +528,21 @@ addArrayExtension("lastIndexOf", simpleFunc)
527528
addArrayExtension("slice", simpleFunc)
528529
addArrayExtension("toString", simpleFunc)
529530
addArrayExtension("toLocaleString", simpleFunc)
531+
addArrayExtension("toSorted", simpleFunc)
532+
addArrayExtension("toSpliced", simpleFunc)
533+
addArrayExtension("with", simpleFunc)
530534
// map
531535
addArrayExtension("every", mapLikeFunc)
532536
addArrayExtension("filter", mapLikeFunc)
533537
addArrayExtension("find", mapLikeFunc)
534538
addArrayExtension("findIndex", mapLikeFunc)
539+
addArrayExtension("findLast", mapLikeFunc)
540+
addArrayExtension("findLastIndex", mapLikeFunc)
535541
addArrayExtension("flatMap", mapLikeFunc)
536542
addArrayExtension("forEach", mapLikeFunc)
537543
addArrayExtension("map", mapLikeFunc)
538544
addArrayExtension("some", mapLikeFunc)
545+
addArrayExtension("toReversed", mapLikeFunc)
539546
// reduce
540547
addArrayExtension("reduce", reduceLikeFunc)
541548
addArrayExtension("reduceRight", reduceLikeFunc)

0 commit comments

Comments
 (0)