Hi,
Since mediawiki.org finally moved to '21, I was able to run the performance tests against production again. We now have a figure for how bad the cold cache experience can be. On an average-sized browser window, the cold cache image load in media viewer takes around 200% of the time it takes for the image to appear on the File: page with a warm cache*. And it takes around 230% of the time for a large browser window. We're talking seconds of difference, that's a long time to wait.
When we first built mmv.bootstrap (the on-demand loading of JS), we didn't have the click catcher (mmv.head). Now that we do, I think we can afford to sacrifice some user bandwidth and just load Media Viewer's JS with the async attribute (which means it wouldn't block page rendering). And mmv.head would take care of catching and replaying clicks that happened before Media Viewer's JS was loaded.
Doing that means we could get rid of mmv.bootstrap entirely, increase the cold cache performance (chances are, the thumbnails on a given page will take longer to load than Media Viewer's JS and CSS) and simplify our code.
Any objections to doing this?
**the reason why we're not comparing figures with the File: page on a cold cache is that it's an unfair comparison: all of mediawiki's JS and CSS would be cold in that case, whereas for Media Viewer it's only Media Viewer's JS and CSS that is cold.*
On Wed, Apr 9, 2014 at 3:03 AM, Gilles Dubuc gilles@wikimedia.org wrote:
Hi,
Since mediawiki.org finally moved to '21, I was able to run the performance tests against production again. We now have a figure for how bad the cold cache experience can be. On an average-sized browser window, the cold cache image load in media viewer takes around 200% of the time it takes for the image to appear on the File: page with a warm cache*. And it takes around 230% of the time for a large browser window. We're talking seconds of difference, that's a long time to wait.
When we first built mmv.bootstrap (the on-demand loading of JS), we didn't have the click catcher (mmv.head). Now that we do, I think we can afford to sacrifice some user bandwidth and just load Media Viewer's JS with the async attribute (which means it wouldn't block page rendering). And mmv.head would take care of catching and replaying clicks that happened before Media Viewer's JS was loaded.
I'm not sure you even need mmv.head -- have you looked at mw.track? (< https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw-method-track%3E). Specifically: "Data handlers are registered via mw.trackSubscribe, and receive the full set of events that match their subscription, including those that fired before the handler was bound."
You can also warm up the localStorage module cache by doing something like:
$( window ).on( 'load', function () { setTimeout( function () { if ( mw.loader.store.enabled && mw.loader.store.get( 'mmv.moduleName' ) === false ) { mw.loader.using( 'mmv.moduleName', mw.loader.store.update ); }
} ); } );
This will wait until the page has loaded and various load handlers have yielded the UI thread before triggering a request for the module and saving it in the localStorage cache.
In the final analysis if you can get the overall asset size down you may be able to justify loading mmv unconditionally, discarding both optimization strategies. You can always offset the impact (and then some) by fixing TimedMediaHandler and mwEmbed to not add unnecessary startup modules, which they currently do unconditionally on all page views.
But: before we get lost in the details, let me zoom out for a second and simply applaud the whole team's approach (collecting data about user experience and analyzing it rigorously) as being exemplary -- well done!
(Also CCing Nuria from Analytics -- she has a lot of relevant experience)
Hi Ori,
have you looked at mw.track?
mw.track seems to be about "analytics events"? What mmv.head does is capture a click jQuery event (the user clicking on a thumbnail) and replaying it once all the necessary dependencies have been loaded. I didn't see anything like that when I glanced at mw.track's and mw.trackSubscribe code, but maybe I didn't dig deep enough.
mmv.head solves the specific situation where users click on a thumbnail very early when the DOM starts appearing on the page, while keeping the amount of blocking JS in the head to a minimum. We thought of trying to make it generic but it turns out that we need to do a lot of mediaviewer-specific stuff inside of it, which would need to go into the head anyway.
I have a feeling TimedMediaHandler started putting things in the head for similar reasons, expect they forgot the part where you only really need the early click capture mechanism in the head, not the entire app's code :) When we get to cleaning TMH, we'll certainly look into whether or not we can make that capture-early-clicks-and-replay-them behavior logic common.
After we've launched to pilot sites and things have cooled down I plan on writing a technical retrospective of Media Viewer, to showcase the "cool parts" and assorted tricks we had to come up with. I'll make sure to ask if there's any interest in moving some of those things to core. And as Gergo has mentioned elsewhere, we need to wait a little for these things to stand the test of wide production use before preaching their benefits.
You can also warm up the localStorage module cache by doing something like
I think this has the same bandwidth implication as loading the JS asynchronously in the footer, which is our main concern at the moment, considering how big media viewer's JS/CSS is.
On Thu, Apr 10, 2014 at 2:17 PM, Ori Livneh ori@wikimedia.org wrote:
On Wed, Apr 9, 2014 at 3:03 AM, Gilles Dubuc gilles@wikimedia.org wrote:
Hi,
Since mediawiki.org finally moved to '21, I was able to run the performance tests against production again. We now have a figure for how bad the cold cache experience can be. On an average-sized browser window, the cold cache image load in media viewer takes around 200% of the time it takes for the image to appear on the File: page with a warm cache*. And it takes around 230% of the time for a large browser window. We're talking seconds of difference, that's a long time to wait.
When we first built mmv.bootstrap (the on-demand loading of JS), we didn't have the click catcher (mmv.head). Now that we do, I think we can afford to sacrifice some user bandwidth and just load Media Viewer's JS with the async attribute (which means it wouldn't block page rendering). And mmv.head would take care of catching and replaying clicks that happened before Media Viewer's JS was loaded.
I'm not sure you even need mmv.head -- have you looked at mw.track? (< https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw-method-track%3E). Specifically: "Data handlers are registered via mw.trackSubscribe, and receive the full set of events that match their subscription, including those that fired before the handler was bound."
You can also warm up the localStorage module cache by doing something like:
$( window ).on( 'load', function () { setTimeout( function () { if ( mw.loader.store.enabled && mw.loader.store.get(
'mmv.moduleName' ) === false ) { mw.loader.using( 'mmv.moduleName', mw.loader.store.update ); }
} ); } );
This will wait until the page has loaded and various load handlers have yielded the UI thread before triggering a request for the module and saving it in the localStorage cache.
In the final analysis if you can get the overall asset size down you may be able to justify loading mmv unconditionally, discarding both optimization strategies. You can always offset the impact (and then some) by fixing TimedMediaHandler and mwEmbed to not add unnecessary startup modules, which they currently do unconditionally on all page views.
But: before we get lost in the details, let me zoom out for a second and simply applaud the whole team's approach (collecting data about user experience and analyzing it rigorously) as being exemplary -- well done!
(Also CCing Nuria from Analytics -- she has a lot of relevant experience)
Multimedia mailing list Multimedia@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/multimedia
Sorry I come a little late to this thread.
After we've launched to pilot sites and things have cooled down I plan on
writing a technical retrospective of Media Viewer, to >>showcase the "cool parts" and assorted tricks we had to come up with. I'll make sure to ask if there's any interest in moving >>some of those things to core. And as Gergo has mentioned elsewhere, we need to wait a little for these things to stand the >>test of wide production use before preaching their benefits.
I would be very interested in seeing a short talk about this, not only about the things that worked but specially about the ones who did not. Maybe could be scheduled as part of the talk series that just started?
When we get to cleaning TMH, we'll certainly look into whether or not we
can make that capture-early-clicks-and-replay-them >behavior logic common. I think the problem here is not so much technical as UX. Technically you could, say, hook an event listener to the window object click event and you could listen for all clicks there and store them for other parts of the application to grab and replay (no idea if this even makes sense in this case, just throwing it out there). The issue would be that it might be the case that a significant amount of time passed until the clicks can be replayed (it's going to depend on assets loading time). It will be confusing for the user to see actions suddenly happening as result of clicks that happen (say) more than 200ms ago.
On Thu, Apr 10, 2014 at 2:56 PM, Gilles Dubuc gilles@wikimedia.org wrote:
Hi Ori,
have you looked at mw.track?
mw.track seems to be about "analytics events"? What mmv.head does is capture a click jQuery event (the user clicking on a thumbnail) and replaying it once all the necessary dependencies have been loaded. I didn't see anything like that when I glanced at mw.track's and mw.trackSubscribe code, but maybe I didn't dig deep enough.
mmv.head solves the specific situation where users click on a thumbnail very early when the DOM starts appearing on the page, while keeping the amount of blocking JS in the head to a minimum. We thought of trying to make it generic but it turns out that we need to do a lot of mediaviewer-specific stuff inside of it, which would need to go into the head anyway.
I have a feeling TimedMediaHandler started putting things in the head for similar reasons, expect they forgot the part where you only really need the early click capture mechanism in the head, not the entire app's code :) When we get to cleaning TMH, we'll certainly look into whether or not we can make that capture-early-clicks-and-replay-them behavior logic common.
After we've launched to pilot sites and things have cooled down I plan on writing a technical retrospective of Media Viewer, to showcase the "cool parts" and assorted tricks we had to come up with. I'll make sure to ask if there's any interest in moving some of those things to core. And as Gergo has mentioned elsewhere, we need to wait a little for these things to stand the test of wide production use before preaching their benefits.
You can also warm up the localStorage module cache by doing something like
I think this has the same bandwidth implication as loading the JS asynchronously in the footer, which is our main concern at the moment, considering how big media viewer's JS/CSS is.
On Thu, Apr 10, 2014 at 2:17 PM, Ori Livneh ori@wikimedia.org wrote:
On Wed, Apr 9, 2014 at 3:03 AM, Gilles Dubuc gilles@wikimedia.orgwrote:
Hi,
Since mediawiki.org finally moved to '21, I was able to run the performance tests against production again. We now have a figure for how bad the cold cache experience can be. On an average-sized browser window, the cold cache image load in media viewer takes around 200% of the time it takes for the image to appear on the File: page with a warm cache*. And it takes around 230% of the time for a large browser window. We're talking seconds of difference, that's a long time to wait.
When we first built mmv.bootstrap (the on-demand loading of JS), we didn't have the click catcher (mmv.head). Now that we do, I think we can afford to sacrifice some user bandwidth and just load Media Viewer's JS with the async attribute (which means it wouldn't block page rendering). And mmv.head would take care of catching and replaying clicks that happened before Media Viewer's JS was loaded.
I'm not sure you even need mmv.head -- have you looked at mw.track? (< https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw-method-track%3E). Specifically: "Data handlers are registered via mw.trackSubscribe, and receive the full set of events that match their subscription, including those that fired before the handler was bound."
You can also warm up the localStorage module cache by doing something like:
$( window ).on( 'load', function () { setTimeout( function () { if ( mw.loader.store.enabled && mw.loader.store.get(
'mmv.moduleName' ) === false ) { mw.loader.using( 'mmv.moduleName', mw.loader.store.update ); }
} ); } );
This will wait until the page has loaded and various load handlers have yielded the UI thread before triggering a request for the module and saving it in the localStorage cache.
In the final analysis if you can get the overall asset size down you may be able to justify loading mmv unconditionally, discarding both optimization strategies. You can always offset the impact (and then some) by fixing TimedMediaHandler and mwEmbed to not add unnecessary startup modules, which they currently do unconditionally on all page views.
But: before we get lost in the details, let me zoom out for a second and simply applaud the whole team's approach (collecting data about user experience and analyzing it rigorously) as being exemplary -- well done!
(Also CCing Nuria from Analytics -- she has a lot of relevant experience)
Multimedia mailing list Multimedia@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/multimedia
multimedia@lists.wikimedia.org