Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of mergeLocaleMessage (#1099) #1101

Merged
merged 1 commit into from
Jan 16, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,12 @@ export default class VueI18n {
if (this._warnHtmlInMessage === 'warn' || this._warnHtmlInMessage === 'error') {
this._checkLocaleMessage(locale, this._warnHtmlInMessage, message)
}
this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message))
this._vm.$set(this._vm.messages, locale, merge(
typeof this._vm.messages[locale] !== 'undefined' && Object.keys(this._vm.messages[locale]).length
? this._vm.messages[locale]
: {},
message
))
Comment on lines +770 to +774
Copy link
Collaborator

@exoego exoego Jan 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for PR 👍

Could you tell me how this change will improve performance when _vm.messages[locale] is undefined or empty object ?
This change introduce Object.keys, which seems to add extra execution time.

I also assume _vm.messages[locale] is likely to have several messages for many cases, so this change will degrade performance for many cases.

Copy link
Contributor Author

@cslee cslee Jan 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi exoego,

this._vm.$set(this._vm.messages, locale, merge({}, this._vm.messages[locale] || {}, message))

With reference to the current logic, the merge call becomes either merge({}, this._vm.messages[locale], message) or merge({}, {}, message) when _vm.messages[locale] is defined or undefined respectively. The merge function loops the messages twice in both cases.

With this change, the messages will only be looped once.

Below simple test gives me the result as follows. The time difference will be greater when there are more messages.

const i18n = new VueI18n({
  locale: 'en',
  messages: {
    ja: { hello: 'world' }
  }
})

const start = process.hrtime()
for (let i = 0; i < 1000000; i++) {
  i18n.mergeLocaleMessage('en', { foo: 'bar' })
}
const end = process.hrtime(start)
console.log(end)

const start2 = process.hrtime()
for (let i = 0; i < 1000000; i++) {
  i18n.mergeLocaleMessage('ja', { foo: 'bar' })
}
const end2 = process.hrtime(start2)
console.log(end2)

// Before the change
// [ 2, 627509043 ]
// [ 3, 271436487 ]

// After the change
// [ 0, 600614057 ]
// [ 0, 417202963 ]

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explanation and quick benchmark.

The time difference will be greater when there are more messages.

Yes, this is exactly the case I am afraid in the previous comment: _vm.messages[locale] is likely to have several messages for many cases, so this change will degrade performance for many cases.

Could you tell more detail of your use case #1099, where mergeLocaleMessage is invoked over undefined or empty message ?

Copy link
Contributor Author

@cslee cslee Jan 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review.

The time difference will be greater when there are more messages.

Sorry for my vague statement, I meant the time difference (before and after the change) will be greater. So the improvement of this pull request will be greater when there are more messages to merge which should be the usual cases.

If I replace { foo: 'bar' } in above benchmark with an object of 10 keys. The result becomes:

// Before the change
// [ 10, 646949552 ]
// [ 11, 363784417 ]

// After the change
// [ 0, 882620796 ]
// [ 0, 689321051 ]

Could you tell more detail of your use case #1099, where mergeLocaleMessage is invoked over undefined or empty message ?

I just tried to improve the performance without logic change. The use case was introduced in #752 by another person and was released in version 8.15.3.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cslee
Thank you for your reporting!
I actually tried to check about performance.

The more locale messages, the more noticeable the performance degradation becomes.
This is a problem.
You can solve the performance degradation with PR.
Thanks! :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change can let watch failed with Vue2.

}

getDateTimeFormat (locale: Locale): DateTimeFormat {
Expand Down