From a486c9a392bf4de838679ef05ca174081df2a5be Mon Sep 17 00:00:00 2001 From: xaviergonz Date: Sun, 24 Mar 2024 11:13:23 +0100 Subject: [PATCH] a bit faster set --- apps/benchmark/src/index.ts | 2 +- .../src/modelShared/sharedInternalModel.ts | 62 +++++++++++++------ 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/apps/benchmark/src/index.ts b/apps/benchmark/src/index.ts index 45f719ca..8e1d0a11 100644 --- a/apps/benchmark/src/index.ts +++ b/apps/benchmark/src/index.ts @@ -23,7 +23,7 @@ const tcModes: (ModelAutoTypeCheckingMode | false)[] = [ ModelAutoTypeCheckingMode.AlwaysOff, ] -const waitBetweenBenchmarks = () => sleep(500) +const waitBetweenBenchmarks = () => sleep(1000) for (const tcMode of tcModes) { let name = "" diff --git a/packages/lib/src/modelShared/sharedInternalModel.ts b/packages/lib/src/modelShared/sharedInternalModel.ts index 5cd7c8ea..56bc0703 100644 --- a/packages/lib/src/modelShared/sharedInternalModel.ts +++ b/packages/lib/src/modelShared/sharedInternalModel.ts @@ -27,12 +27,14 @@ import { assertIsClassOrDataModelClass } from "./utils" function createGetModelInstanceDataField( modelProp: AnyModelProp, modelPropName: string -): (model: M) => unknown { +): (this: M) => unknown { const transformFn = modelProp._transform?.transform if (!transformFn) { // no need to use get since these vars always get on the initial $ - return (model) => model.$[modelPropName] + return function (this) { + return this.$[modelPropName] + } } const transformValue = (model: M, value: unknown) => @@ -42,26 +44,26 @@ function createGetModelInstanceDataField( applySet(model.$, modelPropName, newValue) }) - return (model) => { + return function (this) { // no need to use get since these vars always get on the initial $ - const value = model.$[modelPropName] - return transformValue(model, value) + const value = this.$[modelPropName] + return transformValue(this, value) } } -function setModelInstanceDataField( - model: M, +type SetModelInstanceDataFieldFn = ( modelProp: AnyModelProp, modelPropName: string, + model: M, value: unknown -): void { - // hack to only permit setting these values once fully constructed - // this is to ignore abstract properties being set by babel - // see https://github.com/xaviergonz/mobx-keystone/issues/18 - if (!(model as any)[modelInitializedSymbol]) { - return - } - +) => boolean | void + +const setModelInstanceDataField: SetModelInstanceDataFieldFn = ( + modelProp, + modelPropName, + model, + value +): void => { if (modelProp._setter === "assign" && !getCurrentActionContext()) { // use apply set instead to wrap it in an action applySet(model, modelPropName as any, value) @@ -84,6 +86,22 @@ function setModelInstanceDataField( model.$[modelPropName] = untransformedValue } +const setModelInstanceDataFieldWithPrecheck: SetModelInstanceDataFieldFn = ( + modelProp, + modelPropName, + model, + value +): boolean => { + // hack to only permit setting these values once fully constructed + // this is to ignore abstract properties being set by babel + // see https://github.com/xaviergonz/mobx-keystone/issues/18 + if (!(model as any)[modelInitializedSymbol]) { + return false + } + setModelInstanceDataField(modelProp, modelPropName, model, value) + return true +} + const idGenerator = () => getGlobalConfig().modelIdGenerator() const tPropForId = tProp(typesString, idGenerator) tPropForId._isId = true @@ -246,16 +264,20 @@ export function sharedInternalModel< ThisModel.prototype = Object.create(base.prototype) ThisModel.prototype.constructor = ThisModel + let setFn: SetModelInstanceDataFieldFn = (modelProp, modelPropName, model, value) => { + if (setModelInstanceDataFieldWithPrecheck(modelProp, modelPropName, model, value)) { + setFn = setModelInstanceDataField + } + } + for (const [propName, propData] of Object.entries(modelProps)) { if (!(basePropNames as Set).has(propName)) { const get = createGetModelInstanceDataField(propData, propName) Object.defineProperty(ThisModel.prototype, propName, { - get() { - return get(this) - }, - set(value: any) { - setModelInstanceDataField(this, propData, propName, value) + get, + set(value: unknown) { + setFn(propData, propName, this, value) }, enumerable: true, configurable: false,