SlideShare a Scribd company logo
1 of 93
YUI 3 Loading Strategies
     Yahoo! Search
                             Julien Lecomte
                           F2E Summit 2011
Terminology




 • SRP = Search Results Page
 • RTB = Round Trip Beacon (aka Boomerang)
 • YUI w/o version number will refer to YUI 3




                       -2-               Yahoo! Confidential
What makes a good search results page?




 • Relevant results
 • Easy to scan quickly
 • Fast!




                          -3-            Yahoo! Confidential
The SRP, a very special page




 Performance is a business issue:
 If your web site is not responsive enough,
 you will lose revenue and customer loyalty!




                        -4-              Yahoo! Confidential
The SRP, a very special page




 Web Search is an extremely competitive arena,
 and it brings a significant amount of revenue to
 Yahoo! and its direct competitors.




                        -5-               Yahoo! Confidential
The SRP, a very special page




     Every millisecond and every byte counts!




                        -6-              Yahoo! Confidential
The SRP, a very special page




 Not only does the page need to be fast, it must
 feel fast  Perceived performance is critical!




                        -7-              Yahoo! Confidential
The SRP, a very special page




     Spinners and loading indicators are evil!




                        -8-               Yahoo! Confidential
The SRP, a very special page




                  THIS IS EVIL!




                        -9-       Yahoo! Confidential
The SRP, a very special page




                       THIS IS EVIL!




                        - 10 -         Yahoo! Confidential
The SRP, a very special page




    Reducing time to window.onload
    (without using dirty tricks*) is critical!




(*) Don’t even think about lazy-loading the entire page!
                                             - 11 -        Yahoo! Confidential
The SRP, a very special page




 Q: What does the overwhelming majority of
 users look for in a search results page?




                        - 12 -         Yahoo! Confidential
The SRP, a very special page




              A: The search results!




                        - 13 -         Yahoo! Confidential
The SRP, a very special page




 Although “fancy” features are a differentiating
 factor, they should not get in the way!




                        - 14 -            Yahoo! Confidential
The SRP, a very special page


 Well-designed “fancy” SRP features should:


 • either occupy minimal real estate footprint,
 • or appear only when the user needs it / wants it,
 • or appear towards the bottom of the page,
 • unless it is highly relevant,
 • and never slow down the page!


                             - 15 -               Yahoo! Confidential
Example of a “fancy” feature: “Super Wow”




                      - 16 -           Yahoo! Confidential
Example of a “fancy” feature: “Slide shows”




                       - 17 -            Yahoo! Confidential
Example of a “fancy” feature: “Search Direct”




                        - 18 -           Yahoo! Confidential
Example of a “fancy” feature: “Quick Apps”




                       - 19 -           Yahoo! Confidential
The SRP, a very special page




       Dynamic features require JavaScript.




                        - 20 -           Yahoo! Confidential
The SRP, a very special page




 It is unrealistic to develop complex features
 without a library nowadays…




                        - 21 -             Yahoo! Confidential
The SRP, a very special page




          YUI is the standard at Yahoo!




                        - 22 -            Yahoo! Confidential
The SRP, a very special page




                YUI is awesome…




                        - 23 -    Yahoo! Confidential
The SRP, a very special page




                              …but it’s big!*



(*) when compared to the amount of JavaScript we used to load on the SRP with YUI 2



                                        - 24 -                         Yahoo! Confidential
The SRP, a very special page




 We load 70 KB compressed (gzip) / 210 KB
 uncompressed of JavaScript, most of which is YUI.




                        - 25 -           Yahoo! Confidential
The SRP, a very special page




 Advanced bootstrapping strategies mitigate the
 performance impact of loading a large library.




                        - 26 -          Yahoo! Confidential
Common YUI bootstrapping strategies
Bootstrap: YUI seed

 <script src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script>
 <script>
 YUI().use('node', function (Y) {...});
 </script>




                                  YUI seed

                                                       YUI loader

                                                                    “node” and dependencies…




  8.30 seconds on a modem! (total time for the page to load + download of each JS file)

                                              - 28 -                                 Yahoo! Confidential
Bootstrap: YUI seed + loader

 <script src="http://yui.yahooapis.com/combo?3.3.0/build/yui/yui-
 min.js&3.3.0/build/loader/loader-min.js"></script>
 <script>
 YUI().use('node', function (Y) {...});
 </script>




                                    YUI seed + loader

                                                              “node” and dependencies…




  7.37 seconds on a modem! (total time for the page to load + download of each JS file)

                                                - 29 -                              Yahoo! Confidential
No bootstrap
 <script src="http://yui.yahooapis.com/combo?3.3.0/build/yui/yui-base-
 min.js&3.3.0/build/oop/oop-min.js&3.3.0/build/dom/dom-base-
 min.js&3.3.0/build/dom/selector-native-min.js&3.3.0/build/dom/selector-css2-
 min.js&3.3.0/build/event-custom/event-custom-base-
 min.js&3.3.0/build/event/event-base-min.js&3.3.0/build/pluginhost/pluginhost-
 min.js&3.3.0/build/dom/dom-style-min.js&3.3.0/build/dom/dom-style-ie-
 min.js&3.3.0/build/dom/dom-screen-min.js&3.3.0/build/node/node-
 min.js&3.3.0/build/event/event-base-ie-min.js&3.3.0/build/event/event-delegate-
 min.js"></script>
 <script>
 YUI().use('features', 'node', function (Y) {...});
 </script>




                                      YUI seed + “node” and dependencies…



  5.40 seconds on a modem! (total time for the page to load + download of each JS file)

                                               - 30 -                            Yahoo! Confidential
Lazy-load the YUI seed + loader




                                  YUI seed + loader

                                                            “node” and dependencies…




  7.43 seconds on a modem (total time for the page to load + download of each JS file)
  “artificially” lower RTB but no overall improvement.




                                                 - 31 -                                Yahoo! Confidential
Lazy-load all of the code…




                                     YUI seed + “node” and dependencies…




  5.40 seconds on a modem (total time for the page to load + download of each JS file)
  Same deal: “artificially” lower RTB but no overall improvement.




                                               - 32 -                            Yahoo! Confidential
Lazy-loading, the nitty gritty…
window.onload = function () {
    var d = document,
        h = d.getElementsByTagName("head")[0],
        s = d.createElement("script");

     function init () {
         YUI().use('node', function (Y) {...});
     }

     s.src = '...';
     s.async = 'true';

     if (s.addEventListener) {
         s.addEventListener('load', init, false);
     } else {
         s.onreadystatechange = function () {
             if (s.readyState === 'loaded' || s.readyState === 'complete') {
                 s.onreadystatechange = null;
                 init();
             }
         };
     }
     h.appendChild(s);
};



                                              - 33 -                           Yahoo! Confidential
YLS




 YLS (YUI Loader Service) is a new (awesome)
 way to load YUI modules. Check out Reid’s
 presentation:

 http://reid.github.com/decks/2011/bayjax/yls.html




                               - 34 -                Yahoo! Confidential
The YUI Loader
Old SRP skeleton

 <!doctype html>                           Contains following definitions:
 <html>                                    YUI = ...
   ...                                     Y = ...
   <body>
     ...
     <script src="srp-seed.js"></script>
     <script>
       Y.use('foo', function () { ... feature init code ... });
       Y.use('bar', function () { ... feature init code ... });
       ...
     </script>
   </body>
 </html>
                           Note: we’re using a single global YUI instance (Y)

                               - 36 -                           Yahoo! Confidential
YUI Loader – A trivial example

 var Y = YUI();
 Y.use('json', function () { ... });
 Y.use('profiler', function () { ... });



  2 HTTP requests.
  The profiler module will be loaded after the callback,
 passed to the first Y.use() call, has completed its execution!




                               - 37 -                  Yahoo! Confidential
The problem we’re trying to solve




 The YUI loader is awesome, but it does not yet
 support parallel loading (it’s coming very soon!)




                        - 38 -            Yahoo! Confidential
The problem we’re trying to solve




 Even once the YUI loader supports parallel
 loading, we will still need to first load the seed,
 the loader and its meta-data…




                         - 39 -              Yahoo! Confidential
The problem we’re trying to solve




  That’s 16KB minified and compressed (gzip)…




                       - 40 -          Yahoo! Confidential
The problem we’re trying to solve




   …or 50KB uncompressed (15% of our traffic!)




                       - 41 -           Yahoo! Confidential
The problem we’re trying to solve




             We could lazy-load it…




                       - 42 -         Yahoo! Confidential
The problem we’re trying to solve




 …but we’re still stuck with sequentially loading
 seed + loader first, and then have the loader
 take care of the remainder of the code!




                        - 43 -            Yahoo! Confidential
The problem we’re trying to solve




            Sequential loading is evil!




                        - 44 -            Yahoo! Confidential
What we’re shooting for…




    Lazy-load the YUI seed in parallel with standard
    YUI modules and SRP-specific YUI modules*.



(*) SRP features are implemented as YUI modules.
These modules are “Y.use()’d” mostly from code output inline in the SRP.

                                            - 45 -                         Yahoo! Confidential
What we’re shooting for…




                                      YUI seed + standard YUI modules


                                   Standard YUI modules + SRP-specific YUI modules




 3.17 seconds on a modem! (total time for the page to load + download of each JS file)
 lower RTB because everything is lazy loaded
 large overall improvement thanks to parallel download


                                                    - 46 -                           Yahoo! Confidential
A word of warning…




                     - 47 -   Yahoo! Confidential
A word of warning…




 The tricks you are about to witness are not
 recommended practice!




                        - 48 -            Yahoo! Confidential
A word of warning…




 The YUI team does not support this
 (i.e. you’re pretty much on your own…)




                       - 49 -             Yahoo! Confidential
How to do this?



 • Split code into “bundles” of roughly similar size.
 • The YUI seed is included in one of these bundles.
 • A bundle contains several YUI modules (either
   standard or SRP-specific), and therefore is just a
   series of calls to YUI.add()
 • Lazy-load the bundles from onload handler.




                            - 50 -               Yahoo! Confidential
Huh, will that work?




 NO! The order in which the bundles are downloaded cannot be
 guaranteed i.e. 'YUI' may be undefined when the code inside
 a bundle is evaluated.




                             - 51 -                 Yahoo! Confidential
What about inline scripts?




 We want to make the loading process
 transparent to developers!




                        - 52 -         Yahoo! Confidential
Old SRP skeleton

 <!doctype html>                           Contains following definitions:
 <html>                                    YUI = ...
   ...                                     Y = ...
   <body>
     ...
     <script src="srp-seed.js"></script>
     <script>
       Y.use('foo', function () { ... feature init code ... });
       Y.use('bar', function () { ... feature init code ... });
       ...
     </script>
   </body>
 </html>
                           Note: we’re using a single global YUI instance (Y)

                               - 53 -                           Yahoo! Confidential
What about inline scripts?


 Developers should be able to safely output the
 following code inline:


         Y.use('foo', function () {
               ... feature init code ...
         });




                          - 54 -           Yahoo! Confidential
Huh, will that work?




 NO! Since we want to lazy-load the YUI seed, we cannot have a
 YUI instance created at that point i.e. 'Y' will be undefined.




                               - 55 -                 Yahoo! Confidential
Our solution
New SRP skeleton

 <!doctype html>
 <html>
   ...
   <body>
     ...
     <script>
        YUI = ...;
        Y = ...;
        window.onload = function () { ... Lazy load bundles ... };
        Y.use('foo', function () { ... feature init code ... });
        Y.use('bar', function () { ... feature init code ... });
        ...
     </script>
   </body>
 </html>

                               - 57 -                  Yahoo! Confidential
The fake YUI object (output inline in the SRP)

 YUI = {

      Env: {
          mods: {}
      },

      add: function (name, fn, version, details) {
          YUI.Env.mods[name] = {
              name: name,
              fn: fn,
              version: version,
              details: details || {}
          };
      }
 };


                                - 58 -               Yahoo! Confidential
The fake Y instance (output inline in the SRP)

 Y = {

      pending: [],

      use: function () {
          Y.pending.push(arguments);
      }
 };




                                - 59 -    Yahoo! Confidential
The bundle containing the YUI seed


  • search/yui-override.js
  • yui-3.3.0/yui/yui-base.js
  • yui-3.3.0/yui/yui-later.js
  • yui-3.3.0/collection/array-extras.js
  • yui-3.3.0/yui/get.js
  • yui-3.3.0/yui/features.js
  • yui-3.3.0/oop/oop.js
  • yui-3.3.0/loader/loader.js
  • ...
  • search/srp-core.js



                             - 60 -        Yahoo! Confidential
yui-override.js


 if (typeof YUI !== 'undefined') {
     fakeYUI = YUI;
     YUI = undefined;
 }




                         - 61 -      Yahoo! Confidential
The real YUI instance




 Once the YUI seed has been downloaded,
 we create a real YUI instance.




                        - 62 -        Yahoo! Confidential
The real YUI instance (pseudo code)


 YUI({
       bootstrap: false
 }).use('yui-base', function (Y) {
    1) Save a local reference to the fake YUI instance (global 'Y')
    2) Add the modules that may have been registered with the
         fake YUI object (fakeYUI) to the real YUI object (YUI)
    3) Replace global 'Y' variable by the real YUI instance
       passed to this function.
    4) Process any pending calls to Y.use()

 });



                                    - 63 -                    Yahoo! Confidential
The real YUI instance (pseudo code)


 YUI({
       bootstrap: false
 }).use('yui-base', function (Y) {
    1) Save a local reference to the fake YUI instance (global 'Y')
    2) Add the modules that may have been registered with the
         fake YUI object (fakeYUI) to the real YUI object (YUI)
    3) Replace global 'Y' variable by the real YUI instance
       passed to this function.
    4) Process any pending calls to Y.use()

 });



                                    - 64 -                    Yahoo! Confidential
The real YUI instance (pseudo code)


 YUI({
       bootstrap: false
 }).use('yui-base', function (Y) {
    1) Save a local reference to the fake YUI instance (global 'Y')
    2) Add the modules that may have been registered with the
         fake YUI object (fakeYUI) to the real YUI object (YUI)
    3) Replace global 'Y' variable by the real YUI instance
       passed to this function.
    4) Process any pending calls to Y.use()

 });



                                    - 65 -                    Yahoo! Confidential
The real YUI instance (pseudo code)


 YUI({
       bootstrap: false
 }).use('yui-base', function (Y) {
    1) Save a local reference to the fake YUI instance (global 'Y')
    2) Add the modules that may have been registered with the
         fake YUI object (fakeYUI) to the real YUI object (YUI)
    3) Replace global 'Y' variable by the real YUI instance
       passed to this function.
    4) Process any pending calls to Y.use()

 });



                                    - 66 -                    Yahoo! Confidential
The real YUI instance (pseudo code)


 YUI({
       bootstrap: false
 }).use('yui-base', function (Y) {
    1) Save a local reference to the fake YUI instance (global 'Y')
    2) Add the modules that may have been registered with the
         fake YUI object (fakeYUI) to the real YUI object (YUI)
    3) Replace global 'Y' variable by the real YUI instance
       passed to this function.
    4) Process any pending calls to Y.use()

 });



                                    - 67 -                    Yahoo! Confidential
Huh, will that work?




 NO! When the loader is disabled, the callback function passed
 to Y.use() is invoked, whether or not the dependencies are
 available (a bad design decision IMHO)




                               - 68 -                 Yahoo! Confidential
Modifying the behavior of Y.use()

 YUI({
       bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {
       var pending = [];

       ...

       Y.before(function () {
             If a dependency is missing, do:
                 pending.push(arguments);
                 return new Y.Do.Prevent();
       }, Y, 'use');

       ...
 });



                                       - 69 -             Yahoo! Confidential
Unblocking a pending call to Y.use()


 The availability of a new module (YUI.add)
 may unblock a pending call to Y.use()




                       - 70 -           Yahoo! Confidential
Modifying the behavior of YUI.add()


 YUI({
       bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       ...

       Y.after(function () {
             Process pending queue to see if this newly added
             module may unblock a pending call to Y.use()
       }, YUI, 'add');

       ...
 });




                                       - 71 -                   Yahoo! Confidential
Loading/execution flow (1/2)


             Y.use() invoked


         Compute dependency tree.



                Missing             Yes
                                          Append call to pending queue.
              dependency?

                     No


         Execute standard Y.use()




                                - 72 -                          Yahoo! Confidential
Loading/execution flow (1/2)


             Y.use() invoked


         Compute dependency tree.



                Missing             Yes
                                          Append call to pending queue.
              dependency?

                     No


         Execute standard Y.use()




                                - 73 -                          Yahoo! Confidential
Loading/execution flow (1/2)


             Y.use() invoked


         Compute dependency tree.



                Missing             Yes
                                          Append call to pending queue.
              dependency?

                     No


         Execute standard Y.use()




                                - 74 -                          Yahoo! Confidential
Loading/execution flow (1/2)


             Y.use() invoked


         Compute dependency tree.



                Missing             Yes
                                          Append call to pending queue.
              dependency?

                     No


         Execute standard Y.use()




                                - 75 -                          Yahoo! Confidential
Loading/execution flow (1/2)


             Y.use() invoked


         Compute dependency tree.



                Missing             Yes
                                          Append call to pending queue.
              dependency?

                     No


         Execute standard Y.use()




                                - 76 -                          Yahoo! Confidential
Loading/execution flow (2/2)


          JS bundle downloaded



              YUI.add()




                                           Yes
           Is a call to Y.use()
                                                 Execute pending call.
                 pending?




                                  - 77 -                            Yahoo! Confidential
Loading/execution flow (2/2)


          JS bundle downloaded



              YUI.add()




                                           Yes
           Is a call to Y.use()
                                                 Execute pending call.
                 pending?




                                  - 78 -                            Yahoo! Confidential
Loading/execution flow (2/2)


          JS bundle downloaded



              YUI.add()




                                           Yes
           Is a call to Y.use()
                                                 Execute pending call.
                 pending?




                                  - 79 -                            Yahoo! Confidential
Loading/execution flow (2/2)


          JS bundle downloaded



              YUI.add()




                                           Yes
           Is a call to Y.use()
                                                 Execute pending call.
                 pending?




                                  - 80 -                            Yahoo! Confidential
The code…




            Putting it together…




                     - 81 -        Yahoo! Confidential
srp-core.js (1/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {
   var fakeY = Y.config.win.Y, pending = [];

   Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);

   Y.before(function () {
       If a dependency (direct or indirect) is missing, do:
           pending.push(arguments);
           return new Y.Do.Prevent();
   }, Y, 'use');

   Y.after(function () {
       Process queue to see if this newly added module
       unblocks a pending call to Y.use()
   }, YUI, 'add');

   Y.config.win.Y = Y;

   Y.each(fakeY.pending, function (args) {
       Y.use.apply(Y, args);
   });

   fakeYUI = undefined;

 });


                                                              - 82 -   Yahoo! Confidential
srp-core.js (2/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {



       var fakeY = Y.config.win.Y, pending = [];
       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);

       Y.before(function () {
           If a dependency (direct or indirect) is missing, do:
               pending.push(arguments);
               return new Y.Do.Prevent();
       }, Y, 'use');

       Y.after(function () {
           Process queue to see if this newly added module
           unblocks a pending call to Y.use()
       }, YUI, 'add');

       Y.config.win.Y = Y;

       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });

       fakeYUI = undefined;
 });




                                                                  - 83 -   Yahoo! Confidential
srp-core.js (3/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       var fakeY = Y.config.win.Y, pending = [];



       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);
       Y.before(function () {
           If a dependency (direct or indirect) is missing, do:
               pending.push(arguments);
               return new Y.Do.Prevent();
       }, Y, 'use');

       Y.after(function () {
           Process queue to see if this newly added module
           unblocks a pending call to Y.use()
       }, YUI, 'add');

       Y.config.win.Y = Y;

       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });

       fakeYUI = undefined;
 });




                                                                  - 84 -   Yahoo! Confidential
srp-core.js (4/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       var fakeY = Y.config.win.Y, pending = [];

       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);



       Y.before(function () {
             If a dependency is missing, do:
                 pending.push(arguments);
                 return new Y.Do.Prevent();
       }, Y, 'use');
       Y.after(function () {
           Process queue to see if this newly added module
           unblocks a pending call to Y.use()
       }, YUI, 'add');

       Y.config.win.Y = Y;

       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });

       fakeYUI = undefined;
 });




                                                             - 85 -   Yahoo! Confidential
srp-core.js (5/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       var fakeY = Y.config.win.Y, pending = [];

       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);

       Y.before(function () {
           If a dependency (direct or indirect) is missing, do:
               pending.push(arguments);
               return new Y.Do.Prevent();
       }, Y, 'use');



       Y.after(function () {
             Process queue to see if this newly added module
             unblocks a pending call to Y.use()
       }, YUI, 'add');
       Y.config.win.Y = Y;

       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });

       fakeYUI = undefined;
 });




                                                                  - 86 -   Yahoo! Confidential
srp-core.js (6/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       var fakeY = Y.config.win.Y, pending = [];

       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);

       Y.before(function () {
           If a dependency (direct or indirect) is missing, do:
               pending.push(arguments);
               return new Y.Do.Prevent();
       }, Y, 'use');

       Y.after(function () {
           Process queue to see if this newly added module
           unblocks a pending call to Y.use()
       }, YUI, 'add');



       Y.config.win.Y = Y;
       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });

       fakeYUI = undefined;
 });




                                                                  - 87 -   Yahoo! Confidential
srp-core.js (7/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       var fakeY = Y.config.win.Y, pending = [];

       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);

       Y.before(function () {
           If a dependency (direct or indirect) is missing, do:
               pending.push(arguments);
               return new Y.Do.Prevent();
       }, Y, 'use');

       Y.after(function () {
           Process queue to see if this newly added module
           unblocks a pending call to Y.use()
       }, YUI, 'add');

       Y.config.win.Y = Y;



       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });
       fakeYUI = undefined;
 });




                                                                  - 88 -   Yahoo! Confidential
srp-core.js (8/8)

 YUI({
     bootstrap: false
 }).use('yui-base', 'event-custom-base', function (Y) {

       var fakeY = Y.config.win.Y, pending = [];

       Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true);

       Y.before(function () {
           If a dependency (direct or indirect) is missing, do:
               pending.push(arguments);
               return new Y.Do.Prevent();
       }, Y, 'use');

       Y.after(function () {
           Process queue to see if this newly added module
           unblocks a pending call to Y.use()
       }, YUI, 'add');

       Y.config.win.Y = Y;

       Y.each(fakeY.pending, function (args) {
           Y.use.apply(Y, args);
       });



       fakeYUI = undefined;
 });




                                                                  - 89 -   Yahoo! Confidential
The results
The results…


 • RTB times lower by 40 to 50 msec on broadband
   (that’s considered a significant improvement :)
 • Over 1 second better on dialup connections!




                                - 91 -               Yahoo! Confidential
The holy grail of JavaScript loading on the SRP…


 • Adapt the number of bundles lazy-loaded in
   parallel to the user agent’s capabilities.
 • Reduce the amount of JavaScript we load for
   all page views by moving more of it to on-
   demand loading.




                        - 92 -            Yahoo! Confidential
Questions?


 • jlecomte@yahoo-inc.com
 • http://www.julienlecomte.net/
 • Twitter: @powersander
 • Y!IM: julien.lecomte




                               - 93 -   Yahoo! Confidential

More Related Content

Similar to An unconventional loading strategy for YUI 3

yui3 is Sexy - 使用 YUI 3 的 Sexy Part !
yui3 is Sexy - 使用 YUI 3 的 Sexy Part !yui3 is Sexy - 使用 YUI 3 的 Sexy Part !
yui3 is Sexy - 使用 YUI 3 的 Sexy Part !Joseph Chiang
 
Yui- Yahoo! User Interface Library
Yui- Yahoo! User Interface LibraryYui- Yahoo! User Interface Library
Yui- Yahoo! User Interface LibraryMomentum Design Lab
 
Running YUI 3 on Node.js - JSConf 2010
Running YUI 3 on Node.js - JSConf 2010Running YUI 3 on Node.js - JSConf 2010
Running YUI 3 on Node.js - JSConf 2010Adam Moore
 
Running YUI 3 on Node.js - BayJax
Running YUI 3 on Node.js - BayJaxRunning YUI 3 on Node.js - BayJax
Running YUI 3 on Node.js - BayJaxAdam Moore
 
YUI 3 Loading Strategies - YUIConf2010
YUI 3 Loading Strategies - YUIConf2010YUI 3 Loading Strategies - YUIConf2010
YUI 3 Loading Strategies - YUIConf2010Caridy Patino
 
Server Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yetServer Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yetTom Croucher
 
Let's run JavaScript Everywhere
Let's run JavaScript EverywhereLet's run JavaScript Everywhere
Let's run JavaScript EverywhereTom Croucher
 
Y U I(2)
Y U I(2)Y U I(2)
Y U I(2)tomcoh
 
Build your web apps with yql and yui
Build your web apps with yql and yuiBuild your web apps with yql and yui
Build your web apps with yql and yuiISOCHK
 
Y!OS Overview and Deep Code Dive
Y!OS Overview and Deep Code DiveY!OS Overview and Deep Code Dive
Y!OS Overview and Deep Code DiveJonathan LeBlanc
 
Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...
Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...
Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...Learnosity
 
Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !
Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !
Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !Pierre-jean Texier
 
JavaScript Everywhere! Creating a 100% JavaScript web stack
JavaScript Everywhere! Creating a 100% JavaScript web stackJavaScript Everywhere! Creating a 100% JavaScript web stack
JavaScript Everywhere! Creating a 100% JavaScript web stackTom Croucher
 
From YUI3 to K2
From YUI3 to K2From YUI3 to K2
From YUI3 to K2kaven yan
 
从YUI2到YUI3看前端的演变
从YUI2到YUI3看前端的演变从YUI2到YUI3看前端的演变
从YUI2到YUI3看前端的演变Kejun Zhang
 
EscConf - Deep Dive Frontend Optimization
EscConf - Deep Dive Frontend OptimizationEscConf - Deep Dive Frontend Optimization
EscConf - Deep Dive Frontend OptimizationJonathan Klein
 

Similar to An unconventional loading strategy for YUI 3 (20)

yui3 is Sexy - 使用 YUI 3 的 Sexy Part !
yui3 is Sexy - 使用 YUI 3 的 Sexy Part !yui3 is Sexy - 使用 YUI 3 的 Sexy Part !
yui3 is Sexy - 使用 YUI 3 的 Sexy Part !
 
Yui- Yahoo! User Interface Library
Yui- Yahoo! User Interface LibraryYui- Yahoo! User Interface Library
Yui- Yahoo! User Interface Library
 
Running YUI 3 on Node.js - JSConf 2010
Running YUI 3 on Node.js - JSConf 2010Running YUI 3 on Node.js - JSConf 2010
Running YUI 3 on Node.js - JSConf 2010
 
Running YUI 3 on Node.js - BayJax
Running YUI 3 on Node.js - BayJaxRunning YUI 3 on Node.js - BayJax
Running YUI 3 on Node.js - BayJax
 
YUI 3 Loading Strategies - YUIConf2010
YUI 3 Loading Strategies - YUIConf2010YUI 3 Loading Strategies - YUIConf2010
YUI 3 Loading Strategies - YUIConf2010
 
Server Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yetServer Side JavaScript - You ain't seen nothing yet
Server Side JavaScript - You ain't seen nothing yet
 
Introduction to YUI
Introduction to YUIIntroduction to YUI
Introduction to YUI
 
Technical Introduction to YDN
Technical Introduction to YDNTechnical Introduction to YDN
Technical Introduction to YDN
 
Let's run JavaScript Everywhere
Let's run JavaScript EverywhereLet's run JavaScript Everywhere
Let's run JavaScript Everywhere
 
Y U I(2)
Y U I(2)Y U I(2)
Y U I(2)
 
Build your web apps with yql and yui
Build your web apps with yql and yuiBuild your web apps with yql and yui
Build your web apps with yql and yui
 
Y!OS Overview and Deep Code Dive
Y!OS Overview and Deep Code DiveY!OS Overview and Deep Code Dive
Y!OS Overview and Deep Code Dive
 
Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...
Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...
Educate 2017: Quick 'n Lazy: How we keep things speedy while staying out of y...
 
Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !
Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !
Diving into SWUpdate: adding new platform support in 30minutes with Yocto/OE !
 
Yahoo for the Masses
Yahoo for the MassesYahoo for the Masses
Yahoo for the Masses
 
JavaScript Everywhere! Creating a 100% JavaScript web stack
JavaScript Everywhere! Creating a 100% JavaScript web stackJavaScript Everywhere! Creating a 100% JavaScript web stack
JavaScript Everywhere! Creating a 100% JavaScript web stack
 
From YUI3 to K2
From YUI3 to K2From YUI3 to K2
From YUI3 to K2
 
从YUI2到YUI3看前端的演变
从YUI2到YUI3看前端的演变从YUI2到YUI3看前端的演变
从YUI2到YUI3看前端的演变
 
YUI for your Hacks
YUI for your Hacks YUI for your Hacks
YUI for your Hacks
 
EscConf - Deep Dive Frontend Optimization
EscConf - Deep Dive Frontend OptimizationEscConf - Deep Dive Frontend Optimization
EscConf - Deep Dive Frontend Optimization
 

Recently uploaded

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 

Recently uploaded (20)

Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 

An unconventional loading strategy for YUI 3

  • 1. YUI 3 Loading Strategies Yahoo! Search Julien Lecomte F2E Summit 2011
  • 2. Terminology • SRP = Search Results Page • RTB = Round Trip Beacon (aka Boomerang) • YUI w/o version number will refer to YUI 3 -2- Yahoo! Confidential
  • 3. What makes a good search results page? • Relevant results • Easy to scan quickly • Fast! -3- Yahoo! Confidential
  • 4. The SRP, a very special page Performance is a business issue: If your web site is not responsive enough, you will lose revenue and customer loyalty! -4- Yahoo! Confidential
  • 5. The SRP, a very special page Web Search is an extremely competitive arena, and it brings a significant amount of revenue to Yahoo! and its direct competitors. -5- Yahoo! Confidential
  • 6. The SRP, a very special page Every millisecond and every byte counts! -6- Yahoo! Confidential
  • 7. The SRP, a very special page Not only does the page need to be fast, it must feel fast  Perceived performance is critical! -7- Yahoo! Confidential
  • 8. The SRP, a very special page Spinners and loading indicators are evil! -8- Yahoo! Confidential
  • 9. The SRP, a very special page THIS IS EVIL! -9- Yahoo! Confidential
  • 10. The SRP, a very special page THIS IS EVIL! - 10 - Yahoo! Confidential
  • 11. The SRP, a very special page Reducing time to window.onload (without using dirty tricks*) is critical! (*) Don’t even think about lazy-loading the entire page! - 11 - Yahoo! Confidential
  • 12. The SRP, a very special page Q: What does the overwhelming majority of users look for in a search results page? - 12 - Yahoo! Confidential
  • 13. The SRP, a very special page A: The search results! - 13 - Yahoo! Confidential
  • 14. The SRP, a very special page Although “fancy” features are a differentiating factor, they should not get in the way! - 14 - Yahoo! Confidential
  • 15. The SRP, a very special page Well-designed “fancy” SRP features should: • either occupy minimal real estate footprint, • or appear only when the user needs it / wants it, • or appear towards the bottom of the page, • unless it is highly relevant, • and never slow down the page! - 15 - Yahoo! Confidential
  • 16. Example of a “fancy” feature: “Super Wow” - 16 - Yahoo! Confidential
  • 17. Example of a “fancy” feature: “Slide shows” - 17 - Yahoo! Confidential
  • 18. Example of a “fancy” feature: “Search Direct” - 18 - Yahoo! Confidential
  • 19. Example of a “fancy” feature: “Quick Apps” - 19 - Yahoo! Confidential
  • 20. The SRP, a very special page Dynamic features require JavaScript. - 20 - Yahoo! Confidential
  • 21. The SRP, a very special page It is unrealistic to develop complex features without a library nowadays… - 21 - Yahoo! Confidential
  • 22. The SRP, a very special page YUI is the standard at Yahoo! - 22 - Yahoo! Confidential
  • 23. The SRP, a very special page YUI is awesome… - 23 - Yahoo! Confidential
  • 24. The SRP, a very special page …but it’s big!* (*) when compared to the amount of JavaScript we used to load on the SRP with YUI 2 - 24 - Yahoo! Confidential
  • 25. The SRP, a very special page We load 70 KB compressed (gzip) / 210 KB uncompressed of JavaScript, most of which is YUI. - 25 - Yahoo! Confidential
  • 26. The SRP, a very special page Advanced bootstrapping strategies mitigate the performance impact of loading a large library. - 26 - Yahoo! Confidential
  • 28. Bootstrap: YUI seed <script src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script> <script> YUI().use('node', function (Y) {...}); </script> YUI seed YUI loader “node” and dependencies…  8.30 seconds on a modem! (total time for the page to load + download of each JS file) - 28 - Yahoo! Confidential
  • 29. Bootstrap: YUI seed + loader <script src="http://yui.yahooapis.com/combo?3.3.0/build/yui/yui- min.js&3.3.0/build/loader/loader-min.js"></script> <script> YUI().use('node', function (Y) {...}); </script> YUI seed + loader “node” and dependencies…  7.37 seconds on a modem! (total time for the page to load + download of each JS file) - 29 - Yahoo! Confidential
  • 30. No bootstrap <script src="http://yui.yahooapis.com/combo?3.3.0/build/yui/yui-base- min.js&3.3.0/build/oop/oop-min.js&3.3.0/build/dom/dom-base- min.js&3.3.0/build/dom/selector-native-min.js&3.3.0/build/dom/selector-css2- min.js&3.3.0/build/event-custom/event-custom-base- min.js&3.3.0/build/event/event-base-min.js&3.3.0/build/pluginhost/pluginhost- min.js&3.3.0/build/dom/dom-style-min.js&3.3.0/build/dom/dom-style-ie- min.js&3.3.0/build/dom/dom-screen-min.js&3.3.0/build/node/node- min.js&3.3.0/build/event/event-base-ie-min.js&3.3.0/build/event/event-delegate- min.js"></script> <script> YUI().use('features', 'node', function (Y) {...}); </script> YUI seed + “node” and dependencies…  5.40 seconds on a modem! (total time for the page to load + download of each JS file) - 30 - Yahoo! Confidential
  • 31. Lazy-load the YUI seed + loader YUI seed + loader “node” and dependencies…  7.43 seconds on a modem (total time for the page to load + download of each JS file)  “artificially” lower RTB but no overall improvement. - 31 - Yahoo! Confidential
  • 32. Lazy-load all of the code… YUI seed + “node” and dependencies…  5.40 seconds on a modem (total time for the page to load + download of each JS file)  Same deal: “artificially” lower RTB but no overall improvement. - 32 - Yahoo! Confidential
  • 33. Lazy-loading, the nitty gritty… window.onload = function () { var d = document, h = d.getElementsByTagName("head")[0], s = d.createElement("script"); function init () { YUI().use('node', function (Y) {...}); } s.src = '...'; s.async = 'true'; if (s.addEventListener) { s.addEventListener('load', init, false); } else { s.onreadystatechange = function () { if (s.readyState === 'loaded' || s.readyState === 'complete') { s.onreadystatechange = null; init(); } }; } h.appendChild(s); }; - 33 - Yahoo! Confidential
  • 34. YLS YLS (YUI Loader Service) is a new (awesome) way to load YUI modules. Check out Reid’s presentation: http://reid.github.com/decks/2011/bayjax/yls.html - 34 - Yahoo! Confidential
  • 36. Old SRP skeleton <!doctype html> Contains following definitions: <html> YUI = ... ... Y = ... <body> ... <script src="srp-seed.js"></script> <script> Y.use('foo', function () { ... feature init code ... }); Y.use('bar', function () { ... feature init code ... }); ... </script> </body> </html> Note: we’re using a single global YUI instance (Y) - 36 - Yahoo! Confidential
  • 37. YUI Loader – A trivial example var Y = YUI(); Y.use('json', function () { ... }); Y.use('profiler', function () { ... });  2 HTTP requests.  The profiler module will be loaded after the callback, passed to the first Y.use() call, has completed its execution! - 37 - Yahoo! Confidential
  • 38. The problem we’re trying to solve The YUI loader is awesome, but it does not yet support parallel loading (it’s coming very soon!) - 38 - Yahoo! Confidential
  • 39. The problem we’re trying to solve Even once the YUI loader supports parallel loading, we will still need to first load the seed, the loader and its meta-data… - 39 - Yahoo! Confidential
  • 40. The problem we’re trying to solve That’s 16KB minified and compressed (gzip)… - 40 - Yahoo! Confidential
  • 41. The problem we’re trying to solve …or 50KB uncompressed (15% of our traffic!) - 41 - Yahoo! Confidential
  • 42. The problem we’re trying to solve We could lazy-load it… - 42 - Yahoo! Confidential
  • 43. The problem we’re trying to solve …but we’re still stuck with sequentially loading seed + loader first, and then have the loader take care of the remainder of the code! - 43 - Yahoo! Confidential
  • 44. The problem we’re trying to solve Sequential loading is evil! - 44 - Yahoo! Confidential
  • 45. What we’re shooting for… Lazy-load the YUI seed in parallel with standard YUI modules and SRP-specific YUI modules*. (*) SRP features are implemented as YUI modules. These modules are “Y.use()’d” mostly from code output inline in the SRP. - 45 - Yahoo! Confidential
  • 46. What we’re shooting for… YUI seed + standard YUI modules Standard YUI modules + SRP-specific YUI modules  3.17 seconds on a modem! (total time for the page to load + download of each JS file)  lower RTB because everything is lazy loaded  large overall improvement thanks to parallel download - 46 - Yahoo! Confidential
  • 47. A word of warning… - 47 - Yahoo! Confidential
  • 48. A word of warning… The tricks you are about to witness are not recommended practice! - 48 - Yahoo! Confidential
  • 49. A word of warning… The YUI team does not support this (i.e. you’re pretty much on your own…) - 49 - Yahoo! Confidential
  • 50. How to do this? • Split code into “bundles” of roughly similar size. • The YUI seed is included in one of these bundles. • A bundle contains several YUI modules (either standard or SRP-specific), and therefore is just a series of calls to YUI.add() • Lazy-load the bundles from onload handler. - 50 - Yahoo! Confidential
  • 51. Huh, will that work? NO! The order in which the bundles are downloaded cannot be guaranteed i.e. 'YUI' may be undefined when the code inside a bundle is evaluated. - 51 - Yahoo! Confidential
  • 52. What about inline scripts? We want to make the loading process transparent to developers! - 52 - Yahoo! Confidential
  • 53. Old SRP skeleton <!doctype html> Contains following definitions: <html> YUI = ... ... Y = ... <body> ... <script src="srp-seed.js"></script> <script> Y.use('foo', function () { ... feature init code ... }); Y.use('bar', function () { ... feature init code ... }); ... </script> </body> </html> Note: we’re using a single global YUI instance (Y) - 53 - Yahoo! Confidential
  • 54. What about inline scripts? Developers should be able to safely output the following code inline: Y.use('foo', function () { ... feature init code ... }); - 54 - Yahoo! Confidential
  • 55. Huh, will that work? NO! Since we want to lazy-load the YUI seed, we cannot have a YUI instance created at that point i.e. 'Y' will be undefined. - 55 - Yahoo! Confidential
  • 57. New SRP skeleton <!doctype html> <html> ... <body> ... <script> YUI = ...; Y = ...; window.onload = function () { ... Lazy load bundles ... }; Y.use('foo', function () { ... feature init code ... }); Y.use('bar', function () { ... feature init code ... }); ... </script> </body> </html> - 57 - Yahoo! Confidential
  • 58. The fake YUI object (output inline in the SRP) YUI = { Env: { mods: {} }, add: function (name, fn, version, details) { YUI.Env.mods[name] = { name: name, fn: fn, version: version, details: details || {} }; } }; - 58 - Yahoo! Confidential
  • 59. The fake Y instance (output inline in the SRP) Y = { pending: [], use: function () { Y.pending.push(arguments); } }; - 59 - Yahoo! Confidential
  • 60. The bundle containing the YUI seed • search/yui-override.js • yui-3.3.0/yui/yui-base.js • yui-3.3.0/yui/yui-later.js • yui-3.3.0/collection/array-extras.js • yui-3.3.0/yui/get.js • yui-3.3.0/yui/features.js • yui-3.3.0/oop/oop.js • yui-3.3.0/loader/loader.js • ... • search/srp-core.js - 60 - Yahoo! Confidential
  • 61. yui-override.js if (typeof YUI !== 'undefined') { fakeYUI = YUI; YUI = undefined; } - 61 - Yahoo! Confidential
  • 62. The real YUI instance Once the YUI seed has been downloaded, we create a real YUI instance. - 62 - Yahoo! Confidential
  • 63. The real YUI instance (pseudo code) YUI({ bootstrap: false }).use('yui-base', function (Y) { 1) Save a local reference to the fake YUI instance (global 'Y') 2) Add the modules that may have been registered with the fake YUI object (fakeYUI) to the real YUI object (YUI) 3) Replace global 'Y' variable by the real YUI instance passed to this function. 4) Process any pending calls to Y.use() }); - 63 - Yahoo! Confidential
  • 64. The real YUI instance (pseudo code) YUI({ bootstrap: false }).use('yui-base', function (Y) { 1) Save a local reference to the fake YUI instance (global 'Y') 2) Add the modules that may have been registered with the fake YUI object (fakeYUI) to the real YUI object (YUI) 3) Replace global 'Y' variable by the real YUI instance passed to this function. 4) Process any pending calls to Y.use() }); - 64 - Yahoo! Confidential
  • 65. The real YUI instance (pseudo code) YUI({ bootstrap: false }).use('yui-base', function (Y) { 1) Save a local reference to the fake YUI instance (global 'Y') 2) Add the modules that may have been registered with the fake YUI object (fakeYUI) to the real YUI object (YUI) 3) Replace global 'Y' variable by the real YUI instance passed to this function. 4) Process any pending calls to Y.use() }); - 65 - Yahoo! Confidential
  • 66. The real YUI instance (pseudo code) YUI({ bootstrap: false }).use('yui-base', function (Y) { 1) Save a local reference to the fake YUI instance (global 'Y') 2) Add the modules that may have been registered with the fake YUI object (fakeYUI) to the real YUI object (YUI) 3) Replace global 'Y' variable by the real YUI instance passed to this function. 4) Process any pending calls to Y.use() }); - 66 - Yahoo! Confidential
  • 67. The real YUI instance (pseudo code) YUI({ bootstrap: false }).use('yui-base', function (Y) { 1) Save a local reference to the fake YUI instance (global 'Y') 2) Add the modules that may have been registered with the fake YUI object (fakeYUI) to the real YUI object (YUI) 3) Replace global 'Y' variable by the real YUI instance passed to this function. 4) Process any pending calls to Y.use() }); - 67 - Yahoo! Confidential
  • 68. Huh, will that work? NO! When the loader is disabled, the callback function passed to Y.use() is invoked, whether or not the dependencies are available (a bad design decision IMHO) - 68 - Yahoo! Confidential
  • 69. Modifying the behavior of Y.use() YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var pending = []; ... Y.before(function () { If a dependency is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); ... }); - 69 - Yahoo! Confidential
  • 70. Unblocking a pending call to Y.use() The availability of a new module (YUI.add) may unblock a pending call to Y.use() - 70 - Yahoo! Confidential
  • 71. Modifying the behavior of YUI.add() YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { ... Y.after(function () { Process pending queue to see if this newly added module may unblock a pending call to Y.use() }, YUI, 'add'); ... }); - 71 - Yahoo! Confidential
  • 72. Loading/execution flow (1/2) Y.use() invoked Compute dependency tree. Missing Yes Append call to pending queue. dependency? No Execute standard Y.use() - 72 - Yahoo! Confidential
  • 73. Loading/execution flow (1/2) Y.use() invoked Compute dependency tree. Missing Yes Append call to pending queue. dependency? No Execute standard Y.use() - 73 - Yahoo! Confidential
  • 74. Loading/execution flow (1/2) Y.use() invoked Compute dependency tree. Missing Yes Append call to pending queue. dependency? No Execute standard Y.use() - 74 - Yahoo! Confidential
  • 75. Loading/execution flow (1/2) Y.use() invoked Compute dependency tree. Missing Yes Append call to pending queue. dependency? No Execute standard Y.use() - 75 - Yahoo! Confidential
  • 76. Loading/execution flow (1/2) Y.use() invoked Compute dependency tree. Missing Yes Append call to pending queue. dependency? No Execute standard Y.use() - 76 - Yahoo! Confidential
  • 77. Loading/execution flow (2/2) JS bundle downloaded YUI.add() Yes Is a call to Y.use() Execute pending call. pending? - 77 - Yahoo! Confidential
  • 78. Loading/execution flow (2/2) JS bundle downloaded YUI.add() Yes Is a call to Y.use() Execute pending call. pending? - 78 - Yahoo! Confidential
  • 79. Loading/execution flow (2/2) JS bundle downloaded YUI.add() Yes Is a call to Y.use() Execute pending call. pending? - 79 - Yahoo! Confidential
  • 80. Loading/execution flow (2/2) JS bundle downloaded YUI.add() Yes Is a call to Y.use() Execute pending call. pending? - 80 - Yahoo! Confidential
  • 81. The code… Putting it together… - 81 - Yahoo! Confidential
  • 82. srp-core.js (1/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 82 - Yahoo! Confidential
  • 83. srp-core.js (2/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 83 - Yahoo! Confidential
  • 84. srp-core.js (3/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 84 - Yahoo! Confidential
  • 85. srp-core.js (4/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 85 - Yahoo! Confidential
  • 86. srp-core.js (5/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 86 - Yahoo! Confidential
  • 87. srp-core.js (6/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 87 - Yahoo! Confidential
  • 88. srp-core.js (7/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 88 - Yahoo! Confidential
  • 89. srp-core.js (8/8) YUI({ bootstrap: false }).use('yui-base', 'event-custom-base', function (Y) { var fakeY = Y.config.win.Y, pending = []; Y.mix(YUI.Env, fakeYUI.Env, false, null, 0, true); Y.before(function () { If a dependency (direct or indirect) is missing, do: pending.push(arguments); return new Y.Do.Prevent(); }, Y, 'use'); Y.after(function () { Process queue to see if this newly added module unblocks a pending call to Y.use() }, YUI, 'add'); Y.config.win.Y = Y; Y.each(fakeY.pending, function (args) { Y.use.apply(Y, args); }); fakeYUI = undefined; }); - 89 - Yahoo! Confidential
  • 91. The results… • RTB times lower by 40 to 50 msec on broadband (that’s considered a significant improvement :) • Over 1 second better on dialup connections! - 91 - Yahoo! Confidential
  • 92. The holy grail of JavaScript loading on the SRP… • Adapt the number of bundles lazy-loaded in parallel to the user agent’s capabilities. • Reduce the amount of JavaScript we load for all page views by moving more of it to on- demand loading. - 92 - Yahoo! Confidential
  • 93. Questions? • jlecomte@yahoo-inc.com • http://www.julienlecomte.net/ • Twitter: @powersander • Y!IM: julien.lecomte - 93 - Yahoo! Confidential