I noticed this feature taking a fair amount of time to initialize when enabling the Beta feature.
Here's a summary of a quick performance analysis I did using Chrome Dev Tools' Timeline on a fast desktop machine.
In total CompactInterlanguageList.init() takes 40-50ms (on a fast desktop machine).
* hideOriginal() / showOriginal():
- Forced and blocking style recalculation that causes a needless flash between hiding original and displaying the compact list.
- [x] Move call to hideOriginal() to before render() to combine paints.
- hide(): Lots of needless overhead inside jQuery and Sizzle. See also <https://github.com/jquery/jquery.com/issues/88> and <http://www.learningjquery.com/2010/05/now-you-see-me-showhide-performance>. VisualEditor also learned a lesson from this and improved performance a lot. jQuery hide() is a problematic kitchen sink due to an endless stream of use cases it needs to account for. If you know your code, always use an explicit inline style instead.
- [x] Use plain css() instead.
- show(): Creates inline 'display: list-item;' which is the default.
- ⇒ Use plain css() instead.
- Lots of overhead from Sizzle.attr() and jQuery.access().
- [x] Use plain getAttribute() instead.
- mw.uls.getPreviousLanguages() is deoptimized due to try/catch.
- mw.uls.getPreviousLanguages() is slow due to $.cookie() access.
* compact()->filterByCommonLanguages() [upstream lib: uls]
- mw.uls.getFrequentLanguageList() is slow due to use of getPreviousLanguages().
- mw.uls.getPreviousLanguages() calls $.cookie() – again!
- mw.uls.getPreviousLanguages() also calls $.removeCookie()
- ⇒ Add caching so this second call to $.cookie() isn't done.
- ⇒ Defer the removeCookie() to some future time, doesn't seem important.
- [x] This function seems to be **broken**. It calls various filters that take a list as argument, but it passes no argument so it always goes through a costly fetch only to end up returning an empty list.
* addTrigger() [upstream lib: jquery.i18n]
- Uses browser's HTML parser. Should probably be plain text nstead. It appears $.i18n, contrary to mw.msg, doesn't have a text() mode where only transformation is done but no html creation/escaping. It'd be a lot better to expose plain text directly so there is no need to escape it and then natively parse as HTML. You can inject text into the DOM directly as a text node.
- Takes over 20ms synchronously.
- Forced style calculation, layout, and paint because of call to $trigger.offset().
- ⇒ Maybe figure a way to display this more naturally with the stylesheet relatively instead of requiring inline styles and absolute offsets.
- Called again, when it was already called by compact()
- Re-triggers mw.uls.getFrequentLanguageList(), getPreviousLanguages() and $.cookie() read.
* listen()->uls() [upstream lib: uls]
- Takes over 20ms synchronously (on a high-end desktop machine!).
- Does a whole bunch of things, relating to:
- $.fn.lcd() / LanguageCategoryDisplay
- LanguageCategoryDisplay.append() which does many repeated calls to clearTimeout/setTimeout.
- Includes an avoidable 'Recalculate Style' from show(), css(), detach(), remove(), append(), and more.