SlideShare uma empresa Scribd logo
1 de 45
Baixar para ler offline
GETTING AN “A” IN YSLOW
        Web Performance Optimization 101
     Nick Zadrozny <nick@beyondthepath.com>
HI, MY NAME IS NICK.
     I MAKE WEBSITES.
I’M EMBARRASSED
  MY WEBSITES ARE SLOW
<METAPHOR>
You’re driving a brand new car
It’s moving really slowly

You can smell smoke

People are giving you looks
You’re driving a brand new car
It’s moving really slowly     Return the car

You can smell smoke           Rebuild the car

People are giving you looks   Disengage the hand brake
D’oh!
</METAPHOR>
THE POINT
LOW-HANGING FRUIT…
YAHOO!
THEY MAKE WEBSITES
Yahoo!
          34 “Best Practices” for Exceptional Performance
1. Minimize HTTP            9. Reduce DNS Lookups        19. Reduce the Number of   27. Choose <link> over
   Requests                                                  DOM Elements               @import
                            10. Minify JavaScript and
2. Use a Content                CSS                      20. Split Components       28. Avoid Filters
   Delivery Network                                          Across Domains
                            11. Avoid Redirects                                     29. Optimize Images
3. Add an Expires or a                                   21. Minimize the Number
   Cache-Control            12. Remove Duplicate             of iframes             30. Optimize CSS Sprites
   Header                       Scripts
                                                         22. No 404s                31. Don’t Scale Images in
4. Gzip Components          13. Configure ETags                                         HTML
                                                         23. Reduce Cookie Size
5. Put Stylesheets at the   14. Make Ajax Cacheable                                 32. Make favicon.ico
   Top                                                   24. Use Cookie-free            Small and Cacheable
                            15. Flush the Buffer Early       Domains for
6. Put Scripts at the                                        Components             33. Keep Components
                            16. Use GET for AJAX                                        under 25K (mobile)
   Bottom                       Requests                 25. Minimize DOM
7. Avoid CSS                                                 Access                 34. Pack Components
                            17. Post-load                                               into a Multipart
   Expressions                  Components               26. Develop Smart Event        Document (mobile)
8. Make Javascript and      18. Preload Components           Handlers
   CSS External
YSLOW
PLUGIN FOR FIREBUG
YSlow
                 Tests Your Site on 13 Rules

Minimize HTTP          Put Stylesheets at      Reduce DNS
Requests               the Top                 Lookups

Use a Content          Put Scripts at the      Minify JavaScript
Delivery Network       Bottom                  and CSS

Add an Expires         Avoid CSS               Avoid Redirects
or a Cache-            Expressions
Control Header                                 Remove
                       Make Javascript         Duplicate Scripts
Gzip                   and CSS External
Components                                     Configure ETags
MINIMIZE HTTP REQUESTS
Minimize HTTP Requests

 HTTP Requests are Expensive!
 Net work latency + server latency + net work latency + download time.

 This rule is fundamental, the Catch-All. Everything else is based on it.

 Asset packaging reduces overall number of requests.

 Compression & minification reduce the size of responses.

 Reordering includes lets important stuff go first.

 ETags and Last-Modified checks reduce the content of an HTTP Request.

 Browser caching completely eliminates subsequent requests. Major win.
MAKE JAVASCRIPT
AND CSS EXTERNAL
Make Javascript
             and CSS External
Easier to maintain, less HTML to send

Browser caching prevents later requests

Help order requests by priority

Rails makes this pretty easy,

stylesheet_link_tag
javascript_include_tag
MINIFY JAVASCRIPT
     AND CSS
Minify Javascript and CSS

≈20% size reduction         html,body,div,span,applet,object,iframe,h1,h2
                            ,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,
                            address,big,cite,code,del,dfn,em,font,img,ins

Using a framework? You’re   ,kbd,q,s,samp,small,strike,strong,sub,sup,tt,
                            var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,f
                            orm,label,legend,table,caption,tbody,tfoot,th
probably halfway there.     ead,tr,th,td{margin:0;padding:0;border:
                            0;outline:0;font-size:100%;vertical-
                            align:baseline;background:transparent}
                            body{line-height:1}ol,ul{list-style:none}

YUI Compressor + Rake       blockquote,q{quotes:none}blockquote:before,bl
                            ockquote:after,q:before,q:after{content:'';co
                            ntent:none}:focus{outline:0}ins{text-
                            decoration:none}del{text-decoration:line-
                            through}table{border-collapse:collapse;
                            border-spacing:0}
STYLESHEETS AT THE TOP
SCRIPTS AT THE BOTTOM
Stylesheets at the top
          Scripts at the bottom
                               <!DOCTYPE html>

Javascript shouldn’t block     <html>
                                 <head>

more important rendering
                                   <title>Your Awesome Site</title>
                                   <%= stylesheet_link_tag 'application' %>
                                   <%= yield(:head) %>
                                 </head>
                                 <body>
Pass blocks to the head and        <div id="page">
                                      <header>

foot from within your views:            <h1>Awesome Site</h1>
                                      </header>
                                      <article>
                                        <%= yield %>
<% content_for(:foot) do %>           </article>
  <%= javascript_tag "…" %>        </div>
                                   <%= javascript_include_tag 'application' %>
<% end %>                          <%= yield(:foot) %>
                                 </body>
                               </html>
GZIP COMPONENTS
GZip Components
Another nice size reduction

Most devices support it

CSS, Javascript, text/html,
text/plain
SOME REALLY EASY ONES…
AVOID CSS EXPRESSIONS
AVOID REDIRECTS
REMOVE DUPLICATE
    SCRIPTS
REDUCE DNS LOOKUPS
Apache gives this for free for most of your
assets.

Rails gives this for free for all of the
responses it sends back. It also has some
helpers that will let you potentially skip db
calls and expensive view rendering.




              CONFIGURE ETAGS
Configure ETags

Web servers likely give you a lot for free

Rails gives you some ETagging for free

Rails ETag and Last-Modified helper
def show
  @article = Article.find(params[:id])

  if stale?(:etag => @article, :last_modified => @article.created_at.utc)
    @statistics = @article.really_expensive_call
    respond_to do |format|
      # etc
    end
  end
end
ADD AN EXPIRES OR
CACHE-CONTROL HEADER
Add an Expires Header

Check out mod_expires for Apache

Rails already does “soft” cache busting

Hard cache busting (for CDNs)…

config.action_controller.asset_host =
"http://assets.example.com/#{REVISION}"
USE A CDN
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|

 # Skip directories themselves - we're only interested in files
 unless File.directory?(file)

   # Create an object key from the file name and revision
   key = file.gsub(/.*public//,"#{REVISION}/")

   # Upload the object to S3
   # TODO: make sure we're setting the right headers for gzipped objects
   AWS::S3::S3Object.store(
     key, open(file), bucket,
     :access => :public_read, :expires => 1.year.from_now
   )

   # Increment the progressbar
   progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'
# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|

  # Skip directories themselves - we're only interested in files
  unless File.directory?(file)

    # Create an object key from the file name and revision
    key = file.gsub(/.*public//,"#{REVISION}/")

    # Upload the object to S3
    # TODO: make sure we're setting the right headers for gzipped objects
    AWS::S3::S3Object.store(
      key, open(file), bucket,
      :access => :public_read, :expires => 1.year.from_now
    )

    # Increment the progressbar
    progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'


# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)
# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|

  # Skip directories themselves - we're only interested in files
  unless File.directory?(file)

    # Create an object key from the file name and revision
    key = file.gsub(/.*public//,"#{REVISION}/")

    # Upload the object to S3
    # TODO: make sure we're setting the right headers for gzipped objects
    AWS::S3::S3Object.store(
      key, open(file), bucket,
      :access => :public_read, :expires => 1.year.from_now
    )

    # Increment the progressbar
    progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)


# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)
# Iterate through the files
files.each do |file|

  # Skip directories themselves - we're only interested in files
  unless File.directory?(file)

    # Create an object key from the file name and revision
    key = file.gsub(/.*public//,"#{REVISION}/")

    # Upload the object to S3
    # TODO: make sure we're setting the right headers for gzipped objects
    AWS::S3::S3Object.store(
      key, open(file), bucket,
      :access => :public_read, :expires => 1.year.from_now
    )

    # Increment the progressbar
    progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)


# Iterate through the files
files.each do |file|
 # Skip directories themselves - we're only interested in files
 unless File.directory?(file)

   # Create an object key from the file name and revision
   key = file.gsub(/.*public//,"#{REVISION}/")

   # Upload the object to S3
   # TODO: make sure we're setting the right headers for gzipped objects
   AWS::S3::S3Object.store(
     key, open(file), bucket,
     :access => :public_read, :expires => 1.year.from_now
   )

   # Increment the progressbar
   progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|


   # Skip directories themselves - we're only interested in files
   unless File.directory?(file)
    # Create an object key from the file name and revision
    key = file.gsub(/.*public//,"#{REVISION}/")

    # Upload the object to S3
    # TODO: make sure we're setting the right headers for gzipped objects
    AWS::S3::S3Object.store(
      key, open(file), bucket,
      :access => :public_read, :expires => 1.year.from_now
    )

    # Increment the progressbar
    progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|

  # Skip directories themselves - we're only interested in files
  unless File.directory?(file)


        # Create an object key from the file name and revision
        key = file.gsub(/.*public//,"#{REVISION}/")
    # Upload the object to S3
    # TODO: make sure we're setting the right headers for gzipped objects
    AWS::S3::S3Object.store(
      key, open(file), bucket,
      :access => :public_read, :expires => 1.year.from_now
    )

    # Increment the progressbar
    progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|

  # Skip directories themselves - we're only interested in files
  unless File.directory?(file)

    # Create an object key from the file name and revision
    key = file.gsub(/.*public//,"#{REVISION}/")


        # Upload the object to S3
        # TODO: set the right headers for gzipped objects
        AWS::S3::S3Object.store(
          key, open(file), bucket,
          :access => :public_read, :expires => 1.year.from_now
        )
    # Increment the progressbar
    progressbar.inc

  end
end
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/environment'

require 'aws/s3'
require 'progressbar'

# Set up the S3 configuration and connection
config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV]
bucket = config['bucket_name']
AWS::S3::Base.establish_connection!(
  :access_key_id     => config['access_key_id'],
  :secret_access_key => config['secret_access_key']
)

# Grab everything in the public directory
files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}'))

# Set up the progressbar
progressbar = ProgressBar.new("Uploading...", files.size)

# Iterate through the files
files.each do |file|

 # Skip directories themselves - we're only interested in files
 unless File.directory?(file)

   # Create an object key from the file name and revision
   key = file.gsub(/.*public//,"#{REVISION}/")

   # Upload the object to S3
   # TODO: make sure we're setting the right headers for gzipped objects
   AWS::S3::S3Object.store(
     key, open(file), bucket,
     :access => :public_read, :expires => 1.year.from_now
   )

   # Increment the progressbar
   progressbar.inc

  end
end
THAT’S IT!
Earning an "A" in YSlow
ARTICLE FORTHCOMING
  BEYOND THE PATH.COM

Mais conteúdo relacionado

Destaque

Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...DevGAMM Conference
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationErica Santiago
 
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them wellGood Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them wellSaba Software
 

Destaque (20)

Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy Presentation
 
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them wellGood Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
 

Earning an "A" in YSlow

  • 1. GETTING AN “A” IN YSLOW Web Performance Optimization 101 Nick Zadrozny <nick@beyondthepath.com>
  • 2. HI, MY NAME IS NICK. I MAKE WEBSITES.
  • 3. I’M EMBARRASSED MY WEBSITES ARE SLOW
  • 5. You’re driving a brand new car It’s moving really slowly You can smell smoke People are giving you looks
  • 6. You’re driving a brand new car It’s moving really slowly Return the car You can smell smoke Rebuild the car People are giving you looks Disengage the hand brake
  • 11. Yahoo! 34 “Best Practices” for Exceptional Performance 1. Minimize HTTP 9. Reduce DNS Lookups 19. Reduce the Number of 27. Choose <link> over Requests DOM Elements @import 10. Minify JavaScript and 2. Use a Content CSS 20. Split Components 28. Avoid Filters Delivery Network Across Domains 11. Avoid Redirects 29. Optimize Images 3. Add an Expires or a 21. Minimize the Number Cache-Control 12. Remove Duplicate of iframes 30. Optimize CSS Sprites Header Scripts 22. No 404s 31. Don’t Scale Images in 4. Gzip Components 13. Configure ETags HTML 23. Reduce Cookie Size 5. Put Stylesheets at the 14. Make Ajax Cacheable 32. Make favicon.ico Top 24. Use Cookie-free Small and Cacheable 15. Flush the Buffer Early Domains for 6. Put Scripts at the Components 33. Keep Components 16. Use GET for AJAX under 25K (mobile) Bottom Requests 25. Minimize DOM 7. Avoid CSS Access 34. Pack Components 17. Post-load into a Multipart Expressions Components 26. Develop Smart Event Document (mobile) 8. Make Javascript and 18. Preload Components Handlers CSS External
  • 13. YSlow Tests Your Site on 13 Rules Minimize HTTP Put Stylesheets at Reduce DNS Requests the Top Lookups Use a Content Put Scripts at the Minify JavaScript Delivery Network Bottom and CSS Add an Expires Avoid CSS Avoid Redirects or a Cache- Expressions Control Header Remove Make Javascript Duplicate Scripts Gzip and CSS External Components Configure ETags
  • 15. Minimize HTTP Requests HTTP Requests are Expensive! Net work latency + server latency + net work latency + download time. This rule is fundamental, the Catch-All. Everything else is based on it. Asset packaging reduces overall number of requests. Compression & minification reduce the size of responses. Reordering includes lets important stuff go first. ETags and Last-Modified checks reduce the content of an HTTP Request. Browser caching completely eliminates subsequent requests. Major win.
  • 17. Make Javascript and CSS External Easier to maintain, less HTML to send Browser caching prevents later requests Help order requests by priority Rails makes this pretty easy, stylesheet_link_tag javascript_include_tag
  • 18. MINIFY JAVASCRIPT AND CSS
  • 19. Minify Javascript and CSS ≈20% size reduction html,body,div,span,applet,object,iframe,h1,h2 ,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym, address,big,cite,code,del,dfn,em,font,img,ins Using a framework? You’re ,kbd,q,s,samp,small,strike,strong,sub,sup,tt, var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,f orm,label,legend,table,caption,tbody,tfoot,th probably halfway there. ead,tr,th,td{margin:0;padding:0;border: 0;outline:0;font-size:100%;vertical- align:baseline;background:transparent} body{line-height:1}ol,ul{list-style:none} YUI Compressor + Rake blockquote,q{quotes:none}blockquote:before,bl ockquote:after,q:before,q:after{content:'';co ntent:none}:focus{outline:0}ins{text- decoration:none}del{text-decoration:line- through}table{border-collapse:collapse; border-spacing:0}
  • 20. STYLESHEETS AT THE TOP SCRIPTS AT THE BOTTOM
  • 21. Stylesheets at the top Scripts at the bottom <!DOCTYPE html> Javascript shouldn’t block <html> <head> more important rendering <title>Your Awesome Site</title> <%= stylesheet_link_tag 'application' %> <%= yield(:head) %> </head> <body> Pass blocks to the head and <div id="page"> <header> foot from within your views: <h1>Awesome Site</h1> </header> <article> <%= yield %> <% content_for(:foot) do %> </article> <%= javascript_tag "…" %> </div> <%= javascript_include_tag 'application' %> <% end %> <%= yield(:foot) %> </body> </html>
  • 23. GZip Components Another nice size reduction Most devices support it CSS, Javascript, text/html, text/plain
  • 24. SOME REALLY EASY ONES…
  • 27. REMOVE DUPLICATE SCRIPTS
  • 29. Apache gives this for free for most of your assets. Rails gives this for free for all of the responses it sends back. It also has some helpers that will let you potentially skip db calls and expensive view rendering. CONFIGURE ETAGS
  • 30. Configure ETags Web servers likely give you a lot for free Rails gives you some ETagging for free Rails ETag and Last-Modified helper def show @article = Article.find(params[:id]) if stale?(:etag => @article, :last_modified => @article.created_at.utc) @statistics = @article.really_expensive_call respond_to do |format| # etc end end end
  • 31. ADD AN EXPIRES OR CACHE-CONTROL HEADER
  • 32. Add an Expires Header Check out mod_expires for Apache Rails already does “soft” cache busting Hard cache busting (for CDNs)… config.action_controller.asset_host = "http://assets.example.com/#{REVISION}"
  • 34. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 35. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 36. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 37. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 38. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 39. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 40. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 41. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: set the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 42. #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../config/environment' require 'aws/s3' require 'progressbar' # Set up the S3 configuration and connection config = YAML.load(File.open(File.join(RAILS_ROOT, 'config/amazon_s3.yml')))[RAILS_ENV] bucket = config['bucket_name'] AWS::S3::Base.establish_connection!( :access_key_id => config['access_key_id'], :secret_access_key => config['secret_access_key'] ) # Grab everything in the public directory files = Dir.glob(File.join(RAILS_ROOT, 'public/**/*/**/*.{css,js,gif,jpg,png,…}')) # Set up the progressbar progressbar = ProgressBar.new("Uploading...", files.size) # Iterate through the files files.each do |file| # Skip directories themselves - we're only interested in files unless File.directory?(file) # Create an object key from the file name and revision key = file.gsub(/.*public//,"#{REVISION}/") # Upload the object to S3 # TODO: make sure we're setting the right headers for gzipped objects AWS::S3::S3Object.store( key, open(file), bucket, :access => :public_read, :expires => 1.year.from_now ) # Increment the progressbar progressbar.inc end end
  • 45. ARTICLE FORTHCOMING BEYOND THE PATH.COM

Notas do Editor

  1. \n \n
  2. \n \n
  3. \n \n
  4. \n \n
  5. \n \n
  6. \n \n
  7. \n \n
  8. \n \n
  9. \n \n
  10. \n \n
  11. \n \n
  12. \n \n
  13. \n \n
  14. \n \n
  15. \n \n
  16. \n \n
  17. \n \n
  18. \n \n
  19. \n \n
  20. \n \n
  21. \n \n
  22. \n \n
  23. \n \n
  24. \n \n
  25. \n \n
  26. \n \n
  27. \n \n
  28. \n \n
  29. \n \n
  30. \n \n
  31. \n \n
  32. \n \n
  33. \n \n
  34. \n \n
  35. \n \n
  36. \n \n
  37. \n \n
  38. \n \n
  39. \n \n
  40. \n \n
  41. \n \n
  42. \n \n
  43. \n \n
  44. \n \n
  45. \n \n