mobile & desktop cache 2.0: how to create a scriptable cache

40
DIY Scriptable Cache Guy Podjarny, CTO [email protected] twi;er: @guypod

Upload: blaze-software-inc

Post on 06-Dec-2014

2.874 views

Category:

Technology


2 download

DESCRIPTION

In this webinar, we’ll describe how you can build your own Scriptable Cache based on HTML5 localStorage, making Mobile cache work and giving Desktop Cache a boost. We’ll discuss the value of a Scriptable Cache, show the key elements you’ll need to create, and mention some of the pitfalls you need to beware of.

TRANSCRIPT

Page 1: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

DIY Scriptable Cache Guy  Podjarny,  CTO  [email protected]  twi;er:  @guypod  

Page 2: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Agenda

•  Caching 101 •  Mobile & Desktop Scriptable Cache

– Concept – 6 Steps to Building a Scriptable Cache – Advanced Optimizations

•  Q&A

2  

Page 3: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

The Value of a Scriptable Cache

•  A dedicated cache, not affected by other sites •  A robust cache, not cleared by power cycles •  Better file consolidation

– Works in more cases – Cache Friendly –  Less requests without more bytes

•  Enable Advanced Optimizations – Robust Prefetching, Async CSS/JS…

•  The Secret to Eternal Youth

3  

Page 4: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Not For The Faint of Heart!

•  DIY Scriptable Cache isn’t simple – No magic 3 lines of code

•  Requires HTML & Resource modifications – Some of each

•  The code samples are pseudo-code – They don’t cover all edge cases – They’re not optimized – They probably have syntax errors

4  

Page 5: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Caching 101

Page 6: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

What is a Cache?

•  Storage of previously seen data

•  Reduces costs •  Accelerates results

•  Sample savings: – Computation costs (avoid regenerating

content) – Network costs (avoid retransmitting content)

6  

Page 7: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Cache Types

7  

Browser  -­‐  Eliminates  network  Hme  -­‐  Shared  by  one  user  

Gateway  -­‐  Server  resources  from  the  faster  intranet  -­‐  Shared  per  organizaHon  

CDN  Edge  -­‐  reduces  roundtrip  Hme  –  latency  -­‐  Shared  by  all  users  

Server-­‐Side  -­‐  Reduces  server  load  -­‐  Faster  turnaround  for  response  -­‐  Shared  by  all  users  

Page 8: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Caching - Expiry

•  Cache Expiry Controlled by Headers –  HTTP/1.0: Expires –  HTTP/1.1: Cache-Control

•  ETAG/Last-Modified Enables Conditional GET –  Fetch Resource “If-Modified-Since”

•  CDN/Server Cache can be manually purged

8  

Page 9: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Stale Cache

•  Outdated data in cache – Affects Browser Cache the most

•  Versioning – Add a version number to the filename – Change the version when the file changes – Unique filename = long caching – stale cache

9  

file.v1.js  

var  today  =  “11/10/26”   var  today  =  “11/10/27”  

file.v2.js  

Page 10: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Cache Sizes - Desktop •  Ranges from 75MB to 250MB •  Fits about 90-300 pages

– Average desktop page size is ~800 KB •  Cycles fully every 1-4 days

– Average user browses 88 pages/day

10  

Page 11: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Cache Sizes - Mobile •  Ranges from 0 MB to 25MB •  Fits about 0-60 pages (Average size ~400KB) •  Memory Cache a bit bigger, but volatile

11  

Page 12: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Conclusion

•  Caching is useful and important •  Cache sizes are too small

– Especially on Mobile •  Cache hasn’t evolved with the times

– Stopped evolving with HTTP/1.1 in 2004 •  Browser Cache evolved least of all

– Browsers adding smart eviction only now – Still no script interfaces for smart

caching

12  

Page 13: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Scriptable Cache

Page 14: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Scriptable Browser Cache - Concept

•  A cache accessible via JavaScript – Get/Put/Delete Actions

•  What is it good for? – Cache parts of a page/resource – Adapt to cache state –  Load resources in different ways

•  Why don’t browsers support it today? – Most likely never saw the need – Useful only for advanced websites – Not due to security concerns (at least not good

ones)

14  

Page 15: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Intro to HTML5 localStorage

•  Dedicated Client-Side Storage –  HTML5 standard –  Replaces hacky past solutions

•  Primarily used for logical data –  Game high-score, webmail drafts…

•  Usually limited to 5 MB •  Enables simple get/put/remove commands •  Supported by all modern browsers

–  Desktop: IE8+, Firefox, Safari, Chrome, Opera –  BB 6.0+, most others (http://mobilehtml5.org/)

15  

Page 16: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 0: Utilities

16  

var  sCache  =  {  …          //  Short  name  for  localStorage          db:  localStorage,          //  Method  for  fetching  an  URL  in  sync          getUrlSync:  funcHon  (url)  {                  var  xhr  =  new  XMLH;pRequest();                  xhr.open(  ‘GET’,  url,  false);                  xhr.send(null);                  if  (xhr.status==200)  {  

 return  xhr.responseText;                  }  else  {  

 return  null;                  }          }  …}  

Page 17: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 1: Store & Load Resources

17  

var  sCache  =  {  …          //  Method  for  running  an  external  script          runExtScript:  funcHon  (url)  {                  //  Check  if  the  data  is  in  localStorage                  var  data  =  db.getItem(url);                  if  (!data)  {  

 //  If  not,  fetch  it      data  =  getUrlSync(url);  

   //  Store  it  for  later  use    db.setItem(url,  data);  

               }                  //  Run  the  script  dynamically                  addScriptElement(data);          }  …}  

Page 18: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 2: Recover on error

18  

var  sCache  =  {  …          runExtScript:  funcHon  (url)  {                  //  Check  if  the  data  is  in  localStorage                  var  data  =  db  &&  db.getItem(url);                  if  (!data)  {  

 //  If  not,  fetch  it      data  =  $.get(url);    //  Store  it  for  later  use    try  {  db.setItem(url,  data)  }  catch(e)  {  }  

               }                  //  Run  the  script  dynamically                  addScriptElement(data);          }  …}  

Page 19: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 3: LRU Cache – Cache State

19  

var  sCache  =  {  …          //  Meta-­‐Data  about  the  cache  capacity  and  state            dat:  {size:  0,  capacity:  2*1024*1024,  items:  {}  },          //  Load  the  cache  state  and  items  from  localStorage          load:  funcHon()  {                  var  str  =  db  &&  db.getItem(“cacheData”);                  if  (data)  {  dat  =  JSON.parse(x);  }          },            //  Persist  an  updated  state  to  localStorage          save:  funcHon()  {                  var  str  =  JSON.stringify(dat);                  try  {db.setItem(“cacheData”,  str);  }  catch(e)  {  }          },  …  }  

Page 20: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 3: LRU Cache – Storing items

20  

var  sCache  =  {  …          storeItem:  funcHon(name,  data)  {                  //  Do  nothing  if  the  single  item  is  greater  than  our  capacity                  if  (data.length  >  dat.capacity)  return;                  //  Make  room  for  the  object                  while(dat.items.length  &&  (dat.size  +  data.length)  >  dat.capacity)  {                          var  elem  =  dat.pop();  //  Remove  the  least  recently  used  element                          try  {  db.removeItem(elem.name);  }  catch(e)  {  }                          dat.size  -­‐=  elem.size;                    }                  //  Store  the  new  element  in  localStorage  and  the  cache                  try  {    

 db.setItem(name,  data);    dat.size  +=  data.length;    dat.items.push  ({name:  name,  size:  data.length});  

               }  catch(e)  {  }          }  …    

Page 21: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 3: LRU Cache – Getting items

21  

var  sCache  =  {  …          getItem:  funcHon(name)  {                  //  Try  to  get  the  item                  var  data  =  db  &&  db.getItem(name);                  if  (!data)  return  null;                  //  Move  the  element  to  the  top  of  the  array,  marking  it  as  used                  for(var  i=0;i<dat.items.length;i++)  {  

 if  (dat.items[i].name  ===  name)  {              dat.items.unshiw(dat.items.splice(i,-­‐1));              break;    }  

               }                  return  data;          }  …}  

Page 22: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Post Step 3: Revised Run Script

22  

var  sCache  =  {  …          runExtScript:  funcHon  (url)  {                  //  Check  if  the  data  is  in  the  cache                  var  data  =  getItem(url);                  if  (!data)  {  

 //  If  not,  fetch  it      data  =  $.get(url);    //  Store  it  for  later  use    storeItem(url,  data);  

               }                  //  Run  the  script                  addScriptElement(data);          }  …}  

Page 23: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 4: Versioning

23  

//  Today:  File  version  1  sCache.load();  sCache.runExtScript(‘res.v1.js’);  sCache.save();    //  Tomorrow:  File  version  2  sCache.load();  sCache.runExtScript(‘res.v2.js’);  sCache.save();    //  Old  files  will  implicitly  be  pushed  out  of  the  cache    //  Also  work  with  versioning  using  signature  on  content  

Page 24: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

What Have We Created So Far? •  Scriptable LRU Cache

– Enforces size limits – Recovers from errors

•  Dedicated Cache – Not affected by browsing other sites

•  Robust Cache – Not affected by Mobile Cache Sizes – Survives Power Cycle and Process Reset

•  Still Has Limitations: – Only works on same domain – Resources fetched sequentially

24  

Page 25: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 5: Cross-Domain Resources

•  Why Cross Domain? –  Enables Domain Sharding –  Various Architecture Reasons

•  Solution: Self-Registering Scripts –  Scripts load themselves into the cache –  Added to the page as standard scripts –  Note that one URL stores data as another URL

25  

h;p://1.foo.com/res.v1.js  

alert(1);   sCache.storeItem(  ‘h;p://1.foo.com/res.v1.js’,  ’alert(1)’);  

h;p://1.foo.com/store.res.v1.js  

Page 26: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 6: Fetching Resources In Parallel

26  

<script>sCache.load()</script>    <script>  //  Resources  downloaded  in  parallel  doc.write(“<scr”+”ipt  src=‘h;p://foo.com/store.foo.v1.js’></scr”+”ipt>”);  doc.write(“<scr”+”ipt  src=‘h;p://bar.com/store.bar.v1.js’></scr”+”ipt>”);  </script>    <!-­‐-­‐    Scripts  won’t  run  unHl  previous  ones  complete,  and  data  is  cached  -­‐-­‐>  <script>sCache.runExtScript(‘h;p://foo.com/foo.v1.js’);  </script>  <script>sCache.runExtScript(‘h;p://bar.com/bar.v1.js’);  </script>  <!-­‐-­‐    Note  the  different  URLs!  -­‐-­‐>    <script>sCache.save();</script>  

Page 27: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 6: Parallel Resources + Cache Check

27  

var  sCache  =  {  …          loadResourceViaWrite:  funcHon  (path,  file)  {                  //  Check  if  the  data  is  in  the  cache                  var  data  =  getItem(url);                  if  (!data)  {  

 //  If  not,  doc-­‐write  the  store  URL    doc.write(“<scr”+”ipt  src=‘”  +  path  +              “store.”  +  file  +  //  Add  the  “store.”  prefix            “’></scr”+”ipt>”);  

               }          }  …}  

Page 28: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Step 6: Parallel Downloads, with Cache

28  

<script>sCache.load()</script>    <script>  //  Resources  downloaded  in  parallel,  only  if  needed  sCache.loadResourceViaWrite("h;p://foo.com/”,”foo.v1.js”);  sCache.loadResourceViaWrite("h;p://bar.com/”,”bar.v1.js”);  </script>    <!-­‐-­‐    Scripts  won’t  run  unHl  previous  ones  complete,  and  data  is  cached  -­‐-­‐>  <script>sCache.runExtScript(‘h;p://foo.com/foo.v1.js’);  </script>  <script>sCache.runExtScript(‘h;p://bar.com/bar.v1.js’);  </script>  <!-­‐-­‐    Note  the  different  URLs!  -­‐-­‐>    <script>sCache.save();</script>  

Page 29: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

What Have We Created?

•  Scriptable LRU Cache –  Enforces size limits –  Recovers from errors

•  Dedicated Cache –  Not affected by browsing other sites

•  Robust Cache –  Not affected by Mobile Cache Sizes –  Survives Power Cycle and Process Reset

•  Works across domains •  Resources downloaded in parallel

29  

Page 30: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Understanding localStorage Quota

•  Many browsers use UTF-16 for characters –  Effectively halves the storage space –  Safest to limit capacity to 2 MB

•  Best value: Cache CSS & JavaScript –  Biggest byte-for-byte impact on page load –  Lowest variation allows for longest caching –  Images are borderline too big for capacity

•  Remember: Quotas are per top-level-domain –  *.foo.com share the same quota

30  

Page 31: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Advanced Optimizations

Page 32: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Adaptive Consolidation

•  Fetch Several Resources with One Request –  Store them as Fragments

•  Adapt to Browser Cache State –  If resources aren’t in cache, fetch them as one file –  If some resources are in cache, fetch separate files –  Optionally consolidate missing pieces

32  

h;p://1.foo.com/foo.v1.js  

alert(1);   sCache.storeItem(‘/foo.v1.js’,  ’alert(1)’);  sCache.storeItem(‘/bar.v1.js’,  ’alert(2)’);    

h;p://1.foo.com/store.res.v1.js  

h;p://1.foo.com/bar.v1.js  

alert(2);  

Page 33: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Adaptive vs. Simple Consolidation - #2

•  User browsers Page A, then Page B – Assume each JS file is 20KB in Size

33  

Page  A  

<script  src=“a.js”></script>  <script  src=“b.js”></script>  <script  src=“c.js”></script>  

Page  B  

<script  src=“a.js”></script>  <script  src=“b.js”></script>  

OpGmizaGon   Total  JS  Requests   Total  JS  Bytes  

None   3   60KB  

Simple  ConsolidaHon   2   100KB  

AdapHve  ConsolidaHon   1   60KB  

Page 34: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Adaptive vs. Simple Consolidation - #2

•  User browsers Page A, then Page B – Assume each JS file is 20KB in Size

34  

Page  A  

<script  src=“a.js”></script>  <script  src=“b.js”></script>  <script  src=“c.js”></script>  

Page  B  

<script  src=“a.js”></script>  <script  src=“b.js”></script>  <script  src=“c.js”></script>  <script  src=“d.js”></script>  

OpGmizaGon   Total  JS  Requests   Total  JS  Bytes  

None   4   80KB  

Simple  ConsolidaHon   2   140KB  

AdapHve  ConsolidaHon   2   80KB  

Page 35: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Adaptive vs. Simple Consolidation - #3

•  External & Inline Scripts are often related •  Breaks Simple Consolidation •  Doesn’t break Adaptive Consolidation

35  

Page:   <script  src=“a.js”></script>  <script>  var  userType  =  “user”;  If  (mode==1)  userType  =  “admin”;  </script>  <script  src=“b.js”></script>  

<script>sCache.runExtScript(‘a.js’)</script>  <script>  var  userType  =  “user”;  If  (mode==1)  userType  =  “admin”;  </script>  <script>sCache.runExtScript(‘b.js’)</script>  

a.js   var  mode=1;  

b.js   alert(userType);  

StoreAll.js  sCache.storeItem(‘a.js’,’var  mode=1;’)  sCache.storeItem(‘b.js’,’alert(userType);’)  

OpHmized  Page:  

Page 36: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Robust Prefetching

•  In-Page Prefetching – Fetch CSS/JS Resources at top of page, to be

used later •  Next-Page Prefetching

– Fetch resources for future pages •  Robust and Predictable

– Not invalidated due to content type change in FF – Not invalided by cookies set in IE – Not reloaded when entering same URL in Safari – …

36  

Page 37: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Async JS/CSS

•  Async JS: Run scripts without blocking page – Doable without Scriptable Cache – Scriptable Cache allows script prefetching – Eliminates need to make fetch scripts block

•  Async CSS: Download CSS without blocking – CSS ordinarily delay resource download & render – You can’t always know when a CSS file loaded – Scriptable Cache enables “onload” event – Can still block rendering if desired

37  

Page 38: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Summary

•  Caching is good – you should use it! •  Scriptable Cache is better

– More robust – More reasonably sized on Mobile – Enables important optimizations

•  The two aren’t mutually exclusive –  “store” files should be cacheable –  Images should likely keep using regular cache

38  

Page 39: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

Or… Use the Blaze Scriptable Cache! •  Blaze automates Front-End Optimization

–  No Software, Hardware or Code Changes needed –  All the pitfalls and complexities taken care of

•  Blaze optimizes Mobile & Desktop Websites –  Applying the right optimizations for each client

See how much faster Blaze can make your site with our Free Report: www.blaze.io Contact Us: [email protected]

39  

Page 40: Mobile & Desktop Cache 2.0: How To Create A Scriptable Cache

DIY Scriptable Cache Guy Podjarny, CTO

[email protected] twitter: @guypod

QuesGons?