diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml
new file mode 100644
index 00000000000..a12437f83b4
--- /dev/null
+++ b/.github/linters/.markdown-lint.yml
@@ -0,0 +1,38 @@
+---
+###########################
+###########################
+## Markdown Linter rules ##
+###########################
+###########################
+
+# Linter rules doc:
+# - https://github.com/DavidAnson/markdownlint
+#
+# Note:
+# To comment out a single error:
+#
+# any violations you want
+#
+#
+
+###############
+# Rules by id #
+###############
+MD004: false # Unordered list style
+MD007: false # Allow extra spaces for lists - don't cause issues and will just annoy authors
+MD009: false # Allow trailing spaces - don't cause issues and will just annoy authors
+MD013: false # Don't demand maximum line lengths
+MD024:
+ siblings_only: true # Allows sub-headings to be reused under different headings
+MD026:
+ punctuation: ".,;:!。,;:" # List of not allowed
+MD029: false # Ordered list item prefix
+MD033: false # Allow inline HTML
+MD034: false # Allow base URLs
+MD036: false # Emphasis used instead of a heading
+MD040: false # Don't demand language for all code blocks
+
+#################
+# Rules by tags #
+#################
+blank_lines: false # Error on blank lines
diff --git a/.github/linters/.python-lint b/.github/linters/.python-lint
new file mode 100644
index 00000000000..14581ee88fb
--- /dev/null
+++ b/.github/linters/.python-lint
@@ -0,0 +1,551 @@
+[MASTER]
+errors-only=
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint.
+jobs=1
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Specify a configuration file.
+#rcfile=
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=print-statement,
+ parameter-unpacking,
+ unpacking-in-except,
+ old-raise-syntax,
+ backtick,
+ long-suffix,
+ old-ne-operator,
+ old-octal-literal,
+ import-star-module-level,
+ non-ascii-bytes-literal,
+ raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ locally-enabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ apply-builtin,
+ basestring-builtin,
+ buffer-builtin,
+ cmp-builtin,
+ coerce-builtin,
+ execfile-builtin,
+ file-builtin,
+ long-builtin,
+ raw_input-builtin,
+ reduce-builtin,
+ standarderror-builtin,
+ unicode-builtin,
+ xrange-builtin,
+ coerce-method,
+ delslice-method,
+ getslice-method,
+ setslice-method,
+ no-absolute-import,
+ old-division,
+ dict-iter-method,
+ dict-view-method,
+ next-method-called,
+ metaclass-assignment,
+ indexing-exception,
+ raising-string,
+ reload-builtin,
+ oct-method,
+ hex-method,
+ nonzero-method,
+ cmp-method,
+ input-builtin,
+ round-builtin,
+ intern-builtin,
+ unichr-builtin,
+ map-builtin-not-iterating,
+ zip-builtin-not-iterating,
+ range-builtin-not-iterating,
+ filter-builtin-not-iterating,
+ using-cmp-argument,
+ eq-without-hash,
+ div-method,
+ idiv-method,
+ rdiv-method,
+ exception-message-attribute,
+ invalid-str-codec,
+ sys-max-int,
+ bad-python3-import,
+ deprecated-string-function,
+ deprecated-str-translate-call,
+ deprecated-itertools-function,
+ deprecated-types-field,
+ next-method-defined,
+ dict-items-not-iterating,
+ dict-keys-not-iterating,
+ dict-values-not-iterating
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[REPORTS]
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio).You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages
+reports=no
+
+# Activate the evaluation score.
+score=no
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=optparse.Values,sys.exit
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+ _cb
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=flask,
+ flask_talisman,
+ matplotlib,
+ matplotlib.pyplot,
+ mistune,
+ pandas,
+ scour,
+ werkzeug.routing,
+ werkzeug.http
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+ XXX,
+ TODO
+
+
+[BASIC]
+
+# Naming style matching correct argument names
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style
+#argument-rgx=
+
+# Naming style matching correct attribute names
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,
+ bar,
+ baz,
+ toto,
+ tutu,
+ tata
+
+# Naming style matching correct class attribute names
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style
+#class-attribute-rgx=
+
+# Naming style matching correct class names
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-style
+#class-rgx=
+
+# Naming style matching correct constant names
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ _
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style
+#inlinevar-rgx=
+
+# Naming style matching correct method names
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style
+#method-rgx=
+
+# Naming style matching correct module names
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty
+
+# Naming style matching correct variable names
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style
+#variable-rgx=
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )??$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=trailing-comma,
+ dict-separator
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in a if statement
+max-bool-expr=5
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[IMPORTS]
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,
+ TERMIOS,
+ Bastion,
+ rexec
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
diff --git a/.github/linters/.stylelintrc.json b/.github/linters/.stylelintrc.json
new file mode 100644
index 00000000000..a8381cf9959
--- /dev/null
+++ b/.github/linters/.stylelintrc.json
@@ -0,0 +1,45 @@
+{
+ "extends": "stylelint-config-standard",
+ "rules": {
+ "at-rule-no-unknown": [
+ true,
+ {
+ "ignoreAtRules": ["prince-pdf"]
+ }
+ ],
+ "comment-empty-line-before": null,
+ "font-family-no-duplicate-names": [
+ true,
+ {
+ "ignoreFontFamilyNames": ["monospace"]
+ }
+ ],
+ "length-zero-no-unit": null,
+ "no-descending-specificity": null,
+ "no-eol-whitespace": [
+ true,
+ {
+ "ignore": ["empty-lines"]
+ }
+ ],
+ "property-no-unknown": [
+ true,
+ {
+ "ignoreProperties": ["prince-pdf-display-doc-title","prince-pdf-tag-type"]
+ }
+ ],
+ "selector-list-comma-newline-after": null,
+ "selector-pseudo-element-no-unknown": [
+ true,
+ {
+ "ignorePseudoElements": ["footnote-call","footnote-marker"]
+ }
+ ],
+ "value-keyword-case": [
+ "lower",
+ {
+ "ignoreKeywords": ["Art","A4"]
+ }
+ ]
+ }
+}
diff --git a/.github/workflows/calibreapp-image-action.yml b/.github/workflows/calibreapp-image-action.yml
index 2aec4740c74..c924ff6329a 100644
--- a/.github/workflows/calibreapp-image-action.yml
+++ b/.github/workflows/calibreapp-image-action.yml
@@ -1,3 +1,22 @@
+###########################
+## Calibre Image Action ##
+###########################
+#
+# This runs the calibre GitHub action to compress our images
+#
+# This Action has a few limitations:
+#
+# 1) This currently only works on pull requests from this repo
+# and fails silently for PRs from forks. We've added a PR
+# to handle this better (https://github.com/calibreapp/image-actions/pull/54)
+# and after that can probably combine to the generate_chapters.yml.
+#
+# 2) It seems to only do a basic level of optimisations and better results can
+# be achieved from https://tinypng.com/ or https://squoosh.app/ but not as automated
+# so still good to have this.
+#
+# 3) Currently doesn't handle WebP (https://github.com/calibreapp/image-actions/issues/31)
+#
name: Compress images
on:
pull_request:
diff --git a/.github/workflows/generate_chapters.yml b/.github/workflows/generate_chapters.yml
index 151771bf541..b170781d1ab 100644
--- a/.github/workflows/generate_chapters.yml
+++ b/.github/workflows/generate_chapters.yml
@@ -1,10 +1,14 @@
+######################################
+## Custom Web Almanac GitHub action ##
+######################################
+#
# Updates timestamps, increments CSS, and then runs "npm run generate"
# on any pushes to main for markdown, templates or generate scripts
#
# Then we open a Pull Request for any changes generated.
#
# We do it on a push, rather than on pull request, and only on main to
-# avoid needing GitHub Personal access tokens and to avoid merge conflicts
+# avoid needing GitHub Personal Access Tokens and to avoid merge conflicts
#
name: Generate Chapters on Push
on:
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 00000000000..af09a3ab5e9
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,40 @@
+###########################
+## Linter GitHub Actions ##
+###########################
+#
+# Documentation:
+# https://help.github.com/en/articles/workflow-syntax-for-github-actions
+#
+# For the Web Almanac we have the following rule changes from the defaults:
+# * Markdown - we're a bit more relaxed about this since authors may be less technical
+# * Python - Only change from default is to set ignored-modules=flask, flask-talisman...etc.
+# * CSS - Tweaked to ignore some Prince/Normalise exceptions and some whitespace exceptions
+# * JS - default rules
+# * JSON - default rules
+# * YML - default rules
+# Exception config files are in the .github/linters directory
+#
+name: Lint Code Base
+on:
+ - push
+ - pull_request
+jobs:
+ lint:
+ name: Lint Code Base
+ # Skip duplicate job for local branches
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v2
+ - name: Lint Code Base
+ uses: docker://github/super-linter:v2.2.0
+ env:
+ VALIDATE_ALL_CODEBASE: false
+ DEFAULT_BRANCH: main
+ VALIDATE_YAML: true
+ VALIDATE_JSON: true
+ VALIDATE_PYTHON: true
+ VALIDATE_JAVASCRIPT_ES: true
+ VALIDATE_CSS: true
+ VALIDATE_MD: true
diff --git a/sql/2020/README.md b/sql/2020/README.md
index 8cc7b743828..93b6dd60fc6 100644
--- a/sql/2020/README.md
+++ b/sql/2020/README.md
@@ -1 +1,3 @@
+# Introduction
+
This is the directory for analysts of the 2020 Web Almanac to store queries for their respective chapters.
diff --git a/src/README.md b/src/README.md
index 550b9876d06..a74a35835c7 100644
--- a/src/README.md
+++ b/src/README.md
@@ -1,3 +1,7 @@
+# Developing the Web Almanac
+
+The Web Almanac can be developed on MacOs, Windows or Linux. It required node v12 and python v3 to be installed.
+
## Run Locally
Make sure you run the following commands from within the `src` directory by executing `cd src` first.
diff --git a/src/content/en/2019/caching.md b/src/content/en/2019/caching.md
index a9b952d4b06..4bd83caea75 100644
--- a/src/content/en/2019/caching.md
+++ b/src/content/en/2019/caching.md
@@ -27,12 +27,12 @@ There are three guiding principles to caching web content: cache as much as you
Web architectures typically involve [multiple tiers of caching](https://blog.yoav.ws/tale-of-four-caches/). For example, an HTTP request may have the opportunity to be cached in:
-* An end user's browser
-* A service worker cache in the user's browser
-* A shared gateway
-* CDNs, which offer the ability to cache at the edge, close to end users
-* A caching proxy in front of the application, to reduce the backend workload
-* The application and database layers
+* An end user's browser
+* A service worker cache in the user's browser
+* A shared gateway
+* CDNs, which offer the ability to cache at the edge, close to end users
+* A caching proxy in front of the application, to reduce the backend workload
+* The application and database layers
This chapter will explore how resources are cached within web browsers.
@@ -40,22 +40,22 @@ This chapter will explore how resources are cached within web browsers.
For an HTTP client to cache a resource, it needs to understand two pieces of information:
-* "How long am I allowed to cache this for?"
-* "How do I validate that the content is still fresh?"
+* "How long am I allowed to cache this for?"
+* "How do I validate that the content is still fresh?"
When a web browser sends a response to a client, it typically includes headers that indicate whether the resource is cacheable, how long to cache it for, and how old the resource is. RFC 7234 covers this in more detail in section [4.2 (Freshness)](https://tools.ietf.org/html/rfc7234#section-4.2) and [4.3 (Validation)](https://tools.ietf.org/html/rfc7234#section-4.3).
The HTTP response headers typically used for conveying freshness lifetime are:
-* `Cache-Control` allows you to configure a cache lifetime duration (i.e. how long this is valid for).
-* `Expires` provides an expiration date or time (i.e. when exactly this expires).
+* `Cache-Control` allows you to configure a cache lifetime duration (i.e. how long this is valid for).
+* `Expires` provides an expiration date or time (i.e. when exactly this expires).
`Cache-Control` takes priority if both are present. These are [discussed in more detail below](#cache-control-vs-expires).
The HTTP response headers for validating the responses stored within the cache, i.e. giving conditional requests something to compare to on the server side, are:
-* `Last-Modified` indicates when the object was last changed.
-* Entity Tag (`ETag`) provides a unique identifier for the content.
+* `Last-Modified` indicates when the object was last changed.
+* Entity Tag (`ETag`) provides a unique identifier for the content.
`ETag` takes priority if both are present. These are [discussed in more detail below](#validating-freshness).
@@ -105,9 +105,9 @@ If no caching headers are present in a response, then the [client is permitted t
A cacheable resource is stored by the client for a period of time and available for reuse on a subsequent request. Across all HTTP requests, 80% of responses are considered cacheable, meaning that a cache is permitted to store them. Out of these,
-* 6% of requests have a time to live (TTL) of 0 seconds, which immediately invalidates a cached entry.
-* 27% are cached heuristically because of a missing `Cache-Control` header.
-* 47% are cached for more than 0 seconds.
+* 6% of requests have a time to live (TTL) of 0 seconds, which immediately invalidates a cached entry.
+* 27% are cached heuristically because of a missing `Cache-Control` header.
+* 47% are cached for more than 0 seconds.
The remaining responses are not permitted to be stored in browser caches.
@@ -254,10 +254,10 @@ In HTTP/1.0, the `Expires` header was used to indicate the date/time after which
HTTP/1.1 introduced the `Cache-Control` header, and most modern clients support both headers. This header provides much more extensibility via caching directives. For example:
-* `no-store` can be used to indicate that a resource should not be cached.
-* `max-age` can be used to indicate a freshness lifetime.
-* `must-revalidate` tells the client a cached entry must be validated with a conditional request prior to its use.
-* `private` indicates a response should only be cached by a browser, and not by an intermediary that would serve multiple clients.
+* `no-store` can be used to indicate that a resource should not be cached.
+* `max-age` can be used to indicate a freshness lifetime.
+* `must-revalidate` tells the client a cached entry must be validated with a conditional request prior to its use.
+* `private` indicates a response should only be cached by a browser, and not by an intermediary that would serve multiple clients.
53% of HTTP responses include a `Cache-Control` header with the `max-age` directive, and 54% include the Expires header. However, only 41% of these responses use both headers, which means that 13% of responses are caching solely based on the older `Expires` header.
@@ -343,9 +343,9 @@ For example, `cache-control: public, max-age=43200` indicates that a cached entr
Figure 9 above illustrates the top 15 `Cache-Control` directives in use on mobile websites. The results for desktop and mobile are very similar. There are a few interesting observations about the popularity of these cache directives:
-* `max-age` is used by almost 75% of `Cache-Control` headers, and `no-store` is used by 18%.
-* `public` is rarely necessary since cached entries are assumed `public` unless `private` is specified. Approximately 38% of responses include `public`.
-* The `immutable` directive is relatively new, [introduced in 2017](https://code.facebook.com/posts/557147474482256/this-browser-tweak-saved-60-of-requests-to-facebook) and is [supported on Firefox and Safari](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Browser_compatibility). Its usage has grown to 3.4%, and it is widely used in [Facebook and Google third-party responses](https://discuss.httparchive.org/t/cache-control-immutable-a-year-later/1195).
+* `max-age` is used by almost 75% of `Cache-Control` headers, and `no-store` is used by 18%.
+* `public` is rarely necessary since cached entries are assumed `public` unless `private` is specified. Approximately 38% of responses include `public`.
+* The `immutable` directive is relatively new, [introduced in 2017](https://code.facebook.com/posts/557147474482256/this-browser-tweak-saved-60-of-requests-to-facebook) and is [supported on Firefox and Safari](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Browser_compatibility). Its usage has grown to 3.4%, and it is widely used in [Facebook and Google third-party responses](https://discuss.httparchive.org/t/cache-control-immutable-a-year-later/1195).
Another interesting set of directives to show up in this list are `pre-check` and `post-check`, which are used in 2.2% of `Cache-Control` response headers (approximately 7.8 million responses). This pair of headers was [introduced in Internet Explorer 5 to provide a background validation](https://blogs.msdn.microsoft.com/ieinternals/2009/07/20/internet-explorers-cache-control-extensions/) and was rarely implemented correctly by websites. 99.2% of responses using these headers had used the combination of `pre-check=0` and `post-check=0`. When both of these directives are set to 0, then both directives are ignored. So, it seems these directives were never used correctly!
@@ -357,8 +357,8 @@ When a response is not cacheable, the `Cache-Control` `no-store` directive shoul
There are a few common errors that are made when attempting to configure a response to be non-cacheable:
-* Setting `Cache-Control: no-cache` may sound like the resource will not be cacheable. However, the `no-cache` directive requires the cached entry to be revalidated prior to use and is not the same as being non-cacheable.
-* Setting `Cache-Control: max-age=0` sets the TTL to 0 seconds, but that is not the same as being non-cacheable. When `max-age` is set to 0, the resource is stored in the browser cache and immediately invalidated. This results in the browser having to perform a conditional request to validate the resource's freshness.
+* Setting `Cache-Control: no-cache` may sound like the resource will not be cacheable. However, the `no-cache` directive requires the cached entry to be revalidated prior to use and is not the same as being non-cacheable.
+* Setting `Cache-Control: max-age=0` sets the TTL to 0 seconds, but that is not the same as being non-cacheable. When `max-age` is set to 0, the resource is stored in the browser cache and immediately invalidated. This results in the browser having to perform a conditional request to validate the resource's freshness.
Functionally, `no-cache` and `max-age=0` are similar, since they both require revalidation of a cached resource. The `no-cache` directive can also be used alongside a `max-age` directive that is greater than 0.
@@ -516,9 +516,9 @@ The `Date` HTTP response header is usually generated by the web server or CDN se
Examples of some of the invalid uses of the `Expires` header are:
-* Valid date formats, but using a time zone other than GMT
-* Numerical values such as 0 or -1
-* Values that would be valid in a `Cache-Control` header
+* Valid date formats, but using a time zone other than GMT
+* Numerical values such as 0 or -1
+* Values that would be valid in a `Cache-Control` header
The largest source of invalid `Expires` headers is from assets served from a popular third-party, in which a date/time uses the EST time zone, for example `Expires: Tue, 27 Apr 1971 19:44:06 EST`.
diff --git a/src/content/en/2019/compression.md b/src/content/en/2019/compression.md
index f4fa7910d1f..ed55bd63add 100644
--- a/src/content/en/2019/compression.md
+++ b/src/content/en/2019/compression.md
@@ -19,8 +19,8 @@ HTTP compression is a technique that allows you to encode information using fewe
Compression algorithms are often categorized as lossy or lossless:
-* When a lossy compression algorithm is used, the process is irreversible, and the original file cannot be restored via decompression. This is commonly used to compress media resources, such as image and video content where losing some data will not materially affect the resource.
-* Lossless compression is a completely reversible process, and is commonly used to compress text based resources, such as [HTML](./markup), [JavaScript](./javascript), [CSS](./css), etc.
+* When a lossy compression algorithm is used, the process is irreversible, and the original file cannot be restored via decompression. This is commonly used to compress media resources, such as image and video content where losing some data will not materially affect the resource.
+* Lossless compression is a completely reversible process, and is commonly used to compress text based resources, such as [HTML](./markup), [JavaScript](./javascript), [CSS](./css), etc.
In this chapter, we are going to explore how text-based content is compressed on the web. Analysis of non-text-based content forms part of the [Media](./media) chapter.
@@ -50,9 +50,9 @@ The HTTP Archive contains measurements for 5.3 million web sites, and each site
IANA maintains a [list of valid HTTP content encodings](https://www.iana.org/assignments/http-parameters/http-parameters.xml#content-coding) that can be used with the `Accept-Encoding` and `Content-Encoding` headers. These include gzip, deflate, br (brotli), as well as a few others. Brief descriptions of these algorithms are given below:
-* [Gzip](https://tools.ietf.org/html/rfc1952) uses the [LZ77](https://en.wikipedia.org/wiki/LZ77_and_LZ78#LZ77) and [Huffman coding](https://en.wikipedia.org/wiki/Huffman_coding) compression techniques, and is older than the web itself. It was originally developed for the UNIX gzip program in 1992. An implementation for web delivery has existed since HTTP/1.1, and most web browsers and clients support it.
-* [Deflate](https://tools.ietf.org/html/rfc1951) uses the same algorithm as gzip, just with a different container. Its use was not widely adopted for the web because of [compatibility issues](https://en.wikipedia.org/wiki/HTTP_compression#Problems_preventing_the_use_of_HTTP_compression) with some servers and browsers.
-* [Brotli](https://tools.ietf.org/html/rfc7932) is a newer compression algorithm that was [invented by Google](https://github.com/google/brotli). It uses the combination of a modern variant of the LZ77 algorithm, Huffman coding, and second order context modeling. Compression via brotli is more computationally expensive compared to gzip, but the algorithm is able to reduce files by [15-25%](https://cran.r-project.org/web/packages/brotli/vignettes/brotli-2015-09-22.pdf) more than gzip compression. Brotli was first used for compressing web content in 2015 and is [supported by all modern web browsers](https://caniuse.com/#feat=brotli).
+* [Gzip](https://tools.ietf.org/html/rfc1952) uses the [LZ77](https://en.wikipedia.org/wiki/LZ77_and_LZ78#LZ77) and [Huffman coding](https://en.wikipedia.org/wiki/Huffman_coding) compression techniques, and is older than the web itself. It was originally developed for the UNIX gzip program in 1992. An implementation for web delivery has existed since HTTP/1.1, and most web browsers and clients support it.
+* [Deflate](https://tools.ietf.org/html/rfc1951) uses the same algorithm as gzip, just with a different container. Its use was not widely adopted for the web because of [compatibility issues](https://en.wikipedia.org/wiki/HTTP_compression#Problems_preventing_the_use_of_HTTP_compression) with some servers and browsers.
+* [Brotli](https://tools.ietf.org/html/rfc7932) is a newer compression algorithm that was [invented by Google](https://github.com/google/brotli). It uses the combination of a modern variant of the LZ77 algorithm, Huffman coding, and second order context modeling. Compression via brotli is more computationally expensive compared to gzip, but the algorithm is able to reduce files by [15-25%](https://cran.r-project.org/web/packages/brotli/vignettes/brotli-2015-09-22.pdf) more than gzip compression. Brotli was first used for compressing web content in 2015 and is [supported by all modern web browsers](https://caniuse.com/#feat=brotli).
Approximately 38% of HTTP responses are delivered with text-based compression. This may seem like a surprising statistic, but keep in mind that it is based on all HTTP requests in the dataset. Some content, such as images, will not benefit from these compression algorithms. The table below summarizes the percentage of requests served with each content encoding.
@@ -155,9 +155,9 @@ Additionally, there are 67K requests that return an invalid `Content-Encoding`,
We can't determine the compression levels from any of the diagnostics collected by the HTTP Archive, but the best practice for compressing content is:
-* At a minimum, enable gzip compression level 6 for text based assets. This provides a fair trade-off between computational cost and compression ratio and is the [default for many web servers](https://paulcalvano.com/index.php/2018/07/25/brotli-compression-how-much-will-it-reduce-your-content/)—though [Nginx still defaults to the, often too low, level 1](http://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_comp_level).
-* If you can support brotli and precompress resources, then compress to brotli level 11. This is more computationally expensive than gzip - so precompression is an absolute must to avoid delays.
-* If you can support brotli and are unable to precompress, then compress to brotli level 5. This level will result in smaller payloads compared to gzip, with a similar computational overhead.
+* At a minimum, enable gzip compression level 6 for text based assets. This provides a fair trade-off between computational cost and compression ratio and is the [default for many web servers](https://paulcalvano.com/index.php/2018/07/25/brotli-compression-how-much-will-it-reduce-your-content/)—though [Nginx still defaults to the, often too low, level 1](http://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_comp_level).
+* If you can support brotli and precompress resources, then compress to brotli level 11. This is more computationally expensive than gzip - so precompression is an absolute must to avoid delays.
+* If you can support brotli and are unable to precompress, then compress to brotli level 5. This level will result in smaller payloads compared to gzip, with a similar computational overhead.
## What types of content are we compressing?
diff --git a/src/content/en/2019/ecommerce.md b/src/content/en/2019/ecommerce.md
index 7d03ec5923c..2c7c911e525 100644
--- a/src/content/en/2019/ecommerce.md
+++ b/src/content/en/2019/ecommerce.md
@@ -17,9 +17,9 @@ last_updated: 2020-05-19T00:00:00.000Z
Nearly 10% of the home pages in this study were found to be on an ecommerce platform. An "ecommerce platform" is a set of software or services that enables you to create and operate an online store. There are several types of ecommerce platforms, for example:
-- **Paid-for services** such as [Shopify](https://www.shopify.com/) that host your store and help you get started. They provide website hosting, site and page templates, product-data management, shopping carts and payments.
-- **Software platforms** such as [Magento Open Source](https://magento.com/products/magento-open-source) which you set up, host and manage yourself. These platforms can be powerful and flexible, but may be more complex to set up and run than services such as Shopify.
-- **Hosted platforms** such as [Magento Commerce](https://magento.com/products/magento-commerce) that offer the same features as their self-hosted counterparts, except that hosting is managed as a service by a third-party.
+- **Paid-for services** such as [Shopify](https://www.shopify.com/) that host your store and help you get started. They provide website hosting, site and page templates, product-data management, shopping carts and payments.
+- **Software platforms** such as [Magento Open Source](https://magento.com/products/magento-open-source) which you set up, host and manage yourself. These platforms can be powerful and flexible, but may be more complex to set up and run than services such as Shopify.
+- **Hosted platforms** such as [Magento Commerce](https://magento.com/products/magento-commerce) that offer the same features as their self-hosted counterparts, except that hosting is managed as a service by a third-party.
Figure 1 above shows that we use 373 KB of JavaScript at the 50th percentile, or median. In other words, 50% of all sites ship more than this much JavaScript to their users.
@@ -43,8 +43,8 @@ Looking at these numbers, it's only natural to wonder if this is too much JavaSc
-
Bar chart showing 76 bytes/65 bytes of JavaScript are used in the p10 percentile on desktop and mobile respectively, 186/164 bytes for p25, 391/359 bytes for p50, 721/668 bytes for p75, and 1,131/1,060 bytes for p90.
- Figure 2. Distribution of JavaScript per page by device.
+
Bar chart showing 76 bytes/65 bytes of JavaScript are used in the p10 percentile on desktop and mobile respectively, 186/164 bytes for p25, 391/359 bytes for p50, 721/668 bytes for p75, and 1,131/1,060 bytes for p90.
+ Figure 2. Distribution of JavaScript per page by device.
At every percentile, we're sending slightly more JavaScript to desktop devices than we are to mobile.
@@ -59,8 +59,8 @@ We can get an idea by analyzing main thread processing times for V8 at different
-
Bar chart showing 141 ms/377 ms of processing time is used in the p10 percentile on desktop and mobile respectively, 352/988 ms for p25, 849/2,437 ms for p50, 1,850/5,518 ms for p75, and 3,543/10,735 ms for p90.
- Figure 3. V8 Main thread processing times by device.
+
Bar chart showing 141 ms/377 ms of processing time is used in the p10 percentile on desktop and mobile respectively, 352/988 ms for p25, 849/2,437 ms for p50, 1,850/5,518 ms for p75, and 3,543/10,735 ms for p90.
+ Figure 3. V8 Main thread processing times by device.
At every percentile, processing times are longer for mobile web pages than on desktop. The median total main thread time on desktop is 849 ms, while mobile is at a larger number: 2,437 ms.
@@ -68,11 +68,11 @@ At every percentile, processing times are longer for mobile web pages than on de
Although this data shows how much longer it can take for a mobile device to process JavaScript compared to a more powerful desktop machine, mobile devices also vary in terms of computing power. The following chart shows how processing times on a single web page can vary significantly depending on the mobile device class.
### Number of requests
@@ -83,8 +83,8 @@ One avenue worth exploring when trying to analyze the amount of JavaScript used
-
Bar chart showing 4/4 requests for desktop and mobile respectively are used in the p10 percentile, 10/9 in p25, 19/18 in p50, 33/32 in p75 and 53/52 in p90.
- Figure 5. Distribution of total JavaScript requests.
+
Bar chart showing 4/4 requests for desktop and mobile respectively are used in the p10 percentile, 10/9 in p25, 19/18 in p50, 33/32 in p75 and 53/52 in p90.
+ Figure 5. Distribution of total JavaScript requests.
At the median, 19 requests are sent for desktop and 18 for mobile.
@@ -99,16 +99,16 @@ Third-party JavaScript can come from any external, third-party source. Ads, anal
-
Bar chart showing 0/1 request on desktop are first-party and third-party respectively in p10 percentile, 2/4 in p25, 6/10 in p50, 13/21 in p75, and 24/38 in p90.
- Figure 6. Distribution of first and third-party scripts on desktop.
+
Bar chart showing 0/1 request on desktop are first-party and third-party respectively in p10 percentile, 2/4 in p25, 6/10 in p50, 13/21 in p75, and 24/38 in p90.
+ Figure 6. Distribution of first and third-party scripts on desktop.
For both mobile and desktop clients, more third-party requests are sent than first-party at every percentile. If this seems surprising, let's find out how much actual code shipped comes from third-party vendors.
@@ -117,16 +117,16 @@ For both mobile and desktop clients, more third-party requests are sent than fir
-
Bar chart showing 0/17 bytes of JavaScript are downloaded on desktop for first-party and third-party requests respectively in the p10 percentile, 11/62 in p25, 89/232 in p50, 200/525 in p75, and 404/900 in p90.
- Figure 8. Distribution of total JavaScript downloaded on desktop.
+
Bar chart showing 0/17 bytes of JavaScript are downloaded on desktop for first-party and third-party requests respectively in the p10 percentile, 11/62 in p25, 89/232 in p50, 200/525 in p75, and 404/900 in p90.
+ Figure 8. Distribution of total JavaScript downloaded on desktop.
At the median, 89% more third-party code is used than first-party code authored by the developer for both mobile and desktop. This clearly shows that third-party code can be one of the biggest contributors to bloat. For more information on the impact of third parties, refer to the ["Third Parties"](./third-parties) chapter.
@@ -148,8 +148,8 @@ How many sites are compressing their JavaScript resources?
-
Bar chart showing 67%/65% of JavaScript resources are compressed with gzip on desktop and mobile respectively, and 15%/14% are compressed using Brotli.
- Figure 10. Percentage of sites compressing JavaScript resources with gzip or brotli.
+
Bar chart showing 67%/65% of JavaScript resources are compressed with gzip on desktop and mobile respectively, and 15%/14% are compressed using Brotli.
+ Figure 10. Percentage of sites compressing JavaScript resources with gzip or brotli.
The majority of sites are compressing their JavaScript resources. Gzip encoding is used on ~64-67% of sites and Brotli on ~14%. Compression ratios are similar for both desktop and mobile.
@@ -161,7 +161,7 @@ For a deeper analysis on compression, refer to the ["Compression"](./compression
Open source code, or code with a permissive license that can be accessed, viewed and modified by anyone. From tiny libraries to entire browsers, such as [Chromium](https://www.chromium.org/Home) and [Firefox](https://www.openhub.net/p/firefox), open source code plays a crucial role in the world of web development. In the context of JavaScript, developers rely on open source tooling to include all types of functionality into their web page. Regardless of whether a developer decides to use a small utility library or a massive framework that dictates the architecture of their entire application, relying on open-source packages can make feature development easier and faster. So which JavaScript open-source libraries are used the most?
-
+
Library
@@ -277,7 +277,7 @@ Open source code, or code with a permissive license that can be accessed, viewed
- Figure 11. Top JavaScript libraries on desktop and mobile.
+ Figure 11. Top JavaScript libraries on desktop and mobile.
[jQuery](https://jquery.com/), the most popular JavaScript library ever created, is used in 85.03% of desktop pages and 83.46% of mobile pages. The advent of many Browser APIs and methods, such as [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and [querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector), standardized much of the functionality provided by the library into a native form. Although the popularity of jQuery may seem to be declining, why is it still used in the vast majority of the web?
@@ -299,16 +299,16 @@ In the past number of years, the JavaScript ecosystem has seen a rise in open-so
-
Bar chart showing 4.6% of sites use React, 2.0% AngularJS, 1.8% Backbone.js, 0.8% Vue.js, 0.4% Knockout.js, 0.3% Zone.js, 0.3% Angular, 0.1% AMP, 0.1% Ember.js.
- Figure 12. Most frequently used frameworks on desktop.
+
Bar chart showing 4.6% of sites use React, 2.0% AngularJS, 1.8% Backbone.js, 0.8% Vue.js, 0.4% Knockout.js, 0.3% Zone.js, 0.3% Angular, 0.1% AMP, 0.1% Ember.js.
+ Figure 12. Most frequently used frameworks on desktop.
-Only a subset of popular frameworks are being analyzed here, but it's important to note that all of them either follow one of these two approaches:
+Only a subset of popular frameworks are being analyzed here, but it's important to note that all of them either follow one of these two approaches:
-- A [model-view-controller](https://developer.chrome.com/apps/app_frameworks) (or model-view-viewmodel) architecture
-- A component-based architecture
+- A [model-view-controller](https://developer.chrome.com/apps/app_frameworks) (or model-view-viewmodel) architecture
+- A component-based architecture
-Although there has been a shift towards a component-based model, many older frameworks that follow the MVC paradigm ([AngularJS](https://angularjs.org/), [Backbone.js](https://backbonejs.org/), [Ember](https://emberjs.com/)) are still being used in thousands of pages. However, [React](https://reactjs.org/), [Vue](https://vuejs.org/) and [Angular](https://angular.io/) are the most popular component-based frameworks ([Zone.js](https://github.com/angular/zone.js) is a package that is now part of Angular core).
+Although there has been a shift towards a component-based model, many older frameworks that follow the MVC paradigm ([AngularJS](https://angularjs.org/), [Backbone.js](https://backbonejs.org/), [Ember](https://emberjs.com/)) are still being used in thousands of pages. However, [React](https://reactjs.org/), [Vue](https://vuejs.org/) and [Angular](https://angular.io/) are the most popular component-based frameworks ([Zone.js](https://github.com/angular/zone.js) is a package that is now part of Angular core).
## Differential loading
@@ -326,8 +326,8 @@ How many sites use `type="module"` for scripts on their page?
-
Bar chart showing 0.6% of sites on desktop use 'type=module', and 0.8% of sites on mobile.
- Figure 13. Percentage of sites utilizing type=module.
+
Bar chart showing 0.6% of sites on desktop use 'type=module', and 0.8% of sites on mobile.
+ Figure 13. Percentage of sites utilizing type=module.
Browser-level support for modules is still relatively new, and the numbers here show that very few sites currently use `type="module"` for their scripts. Many sites are still relying on module loaders (2.37% of all desktop sites use [RequireJS](https://github.com/requirejs/requirejs) for example) and bundlers ([webpack](https://webpack.js.org/) for example) to define modules within their codebase.
@@ -344,8 +344,8 @@ When used together, browsers that support modules will completely ignore any scr
-
Bar chart showing 0.8% of sites on desktop use 'nomobule', and 0.5% of sites on mobile.
- Figure 14. Percentage of sites using nomodule.
+
Bar chart showing 0.8% of sites on desktop use 'nomobule', and 0.5% of sites on mobile.
+ Figure 14. Percentage of sites using nomodule.
Similarly, very few sites (0.50%-0.80%) use the `nomodule` attribute for any scripts.
@@ -363,8 +363,8 @@ So, how many sites use preload and prefetch directives?
-
Bar chart showing 14% of sites on desktop use rel=preload' for scripts, and 15% of sites on mobile.
- Figure 15. Percentage of sites using rel=preload for scripts.
+
Bar chart showing 14% of sites on desktop use rel=preload' for scripts, and 15% of sites on mobile.
+ Figure 15. Percentage of sites using rel=preload for scripts.
For all sites measured in HTTP Archive, 14.33% of desktop sites and 14.84% of mobile sites use `` for scripts on their page.
@@ -375,8 +375,8 @@ For prefetch, we have the following:
-
Bar chart showing 0.08% of sites on desktop use 'rel=prefetch', and 0.08% of sites on mobile.
- Figure 16. Percentage of sites using rel=prefetch for scripts.
+
Bar chart showing 0.08% of sites on desktop use 'rel=prefetch', and 0.08% of sites on mobile.
+ Figure 16. Percentage of sites using rel=prefetch for scripts.
For both mobile and desktop, 0.08% of pages leverage prefetch for any of their scripts.
@@ -400,8 +400,8 @@ How many sites use the following APIs?
-
Bar chart showing 25.5%/36.2% of sites on desktop and mobile respectivdely use WeakMap, 6.1%/17.2% use WeakSet, 3.9%/14.0% use Intl, 3.9%/4.4% use Proxy, 0.4%/0.4% use Atomics, and 0.2%/0.2% use SharedArrayBuffer.
- Figure 17. Usage of new JavaScript APIs.
+
Bar chart showing 25.5%/36.2% of sites on desktop and mobile respectivdely use WeakMap, 6.1%/17.2% use WeakSet, 3.9%/14.0% use Intl, 3.9%/4.4% use Proxy, 0.4%/0.4% use Atomics, and 0.2%/0.2% use SharedArrayBuffer.
+ Figure 17. Usage of new JavaScript APIs.
Atomics (0.38%) and SharedArrayBuffer (0.20%) are barely visible on this chart since they are used on such few pages.
@@ -420,8 +420,8 @@ Although useful, there are a number of reasons why many sites may not want to in
-
Bar chart showing 18% of desktop sites and 17% of mobile sites use source maps.
- Figure 18. Percentage of sites using source maps.
+
Bar chart showing 18% of desktop sites and 17% of mobile sites use source maps.
+ Figure 18. Percentage of sites using source maps.
For both desktop and mobile pages, the results are about the same. 17-18% include a source map for at least one script on the page (detected as a first-party script with `sourceMappingURL`).
diff --git a/src/content/en/2019/markup.md b/src/content/en/2019/markup.md
index 5b5482d768e..ce5e761eee7 100644
--- a/src/content/en/2019/markup.md
+++ b/src/content/en/2019/markup.md
@@ -17,7 +17,7 @@ last_updated: 2020-03-01T00:00:00.000Z
In 2005, Ian "Hixie" Hickson posted [some analysis of markup data](https://web.archive.org/web/20060203035414/http://code.google.com/webstats/index.html) building upon various previous work. Much of this work aimed to investigate class names to see if there were common informal semantics that were being adopted by developers which it might make sense to standardize upon. Some of this research helped inform new elements in HTML5.
-14 years later, it's time to take a fresh look. Since then, we've also had the introduction of [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) and the [Extensible Web Manifesto](https://extensiblewebmanifesto.org/) encouraging that we find better ways to pave the cowpaths by allowing developers to explore the space of elements themselves and allow standards bodies to[ act more like dictionary editors](https://bkardell.com/blog/Dropping-The-F-Bomb-On-Standards.html). Unlike CSS class names, which might be used for anything, we can be far more certain that authors who used a non-standard *element* really intended this to be an element.
+14 years later, it's time to take a fresh look. Since then, we've also had the introduction of [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) and the [Extensible Web Manifesto](https://extensiblewebmanifesto.org/) encouraging that we find better ways to pave the cowpaths by allowing developers to explore the space of elements themselves and allow standards bodies to [act more like dictionary editors](https://bkardell.com/blog/Dropping-The-F-Bomb-On-Standards.html). Unlike CSS class names, which might be used for anything, we can be far more certain that authors who used a non-standard *element* really intended this to be an element.
As of July 2019, the HTTP Archive has begun collecting all used *element* names in the DOM for about 4.4 million desktop home pages, and about 5.3 million mobile home pages which we can now begin to research and dissect. _(Learn more about our [Methodology](./methodology).)_
diff --git a/src/content/en/2019/resource-hints.md b/src/content/en/2019/resource-hints.md
index ae600b05097..244f67e3a0e 100644
--- a/src/content/en/2019/resource-hints.md
+++ b/src/content/en/2019/resource-hints.md
@@ -19,9 +19,9 @@ last_updated: 2020-03-02T00:00:00.000Z
[Examples](https://youtu.be/YJGCZCaIZkQ?t=1956) of performance improvements as a result of resource hints include:
-* Jabong decreased Time to Interactive by 1.5 seconds by preloading critical scripts.
-* Barefoot Wine decreased Time to Interactive of future pages by 2.7 seconds by prefetching visible links.
-* Chrome.com decreased latency by 0.7 seconds by preconnecting to critical origins.
+* Jabong decreased Time to Interactive by 1.5 seconds by preloading critical scripts.
+* Barefoot Wine decreased Time to Interactive of future pages by 2.7 seconds by prefetching visible links.
+* Chrome.com decreased latency by 0.7 seconds by preconnecting to critical origins.
There are four separate resource hints supported by most browsers today: `dns-prefetch`, `preconnect`, `preload`, and `prefetch`.
diff --git a/src/content/en/2019/security.md b/src/content/en/2019/security.md
index 06efeb00054..081081a0acd 100644
--- a/src/content/en/2019/security.md
+++ b/src/content/en/2019/security.md
@@ -166,7 +166,7 @@ The [HSTS](https://tools.ietf.org/html/rfc6797) header allows a website to instr
Figure 9. HSTS directive usage.
-Less than 15% of mobile and desktop pages are issuing a HSTS with a `max-age ` directive. This is a minimum requirement for a valid policy. Fewer still are including subdomains in their policy with the `includeSubDomains` directive and even fewer still are HSTS preloading. Looking at the median value for a HSTS `max-age`, for those that do use this, we can see that on both desktop and mobile it is 15768000, a strong configuration representing half a year (60 x 60 x 24 x 365/2).
+Less than 15% of mobile and desktop pages are issuing a HSTS with a `max-age` directive. This is a minimum requirement for a valid policy. Fewer still are including subdomains in their policy with the `includeSubDomains` directive and even fewer still are HSTS preloading. Looking at the median value for a HSTS `max-age`, for those that do use this, we can see that on both desktop and mobile it is 15768000, a strong configuration representing half a year (60 x 60 x 24 x 365/2).
@@ -272,10 +272,10 @@ A total of 3.25% of desktop pages and 2.95% of mobile pages issue a `Referrer-Po
| `no-referrer-when-downgrade` | 39.16% | 41.52% |
| `strict-origin-when-cross-origin` | 39.16% | 22.17% |
| `unsafe-url` | 22.17% | 22.17% |
-| `same-origin ` | 7.97% | 7.97% |
+| `same-origin` | 7.97% | 7.97% |
| `origin-when-cross-origin` | 6.76% | 6.44% |
| `no-referrer` | 5.65% | 5.38% |
-| `strict-origin ` | 4.35% | 4.14% |
+| `strict-origin` | 4.35% | 4.14% |
| `origin` | 3.63% | 3.23% |
Figure 11. `Referrer-Policy` configuration option usage.
diff --git a/src/content/es/2019/javascript.md b/src/content/es/2019/javascript.md
index e2266e2896f..13586cb4421 100644
--- a/src/content/es/2019/javascript.md
+++ b/src/content/es/2019/javascript.md
@@ -31,8 +31,8 @@ Enviar paquetes de JavaScript más pequeños al navegador es la mejor manera de
-
Gráfico de barras que muestra que 70 bytes de JavaScript se usa en el percentil p10, 174 bytes para p25, 373 bytes para p50, 693 bytes para p75 y 1.093 bytes para p90
- Figura 1. Distribución de bytes de JavaScript por página.
+
Gráfico de barras que muestra que 70 bytes de JavaScript se usa en el percentil p10, 174 bytes para p25, 373 bytes para p50, 693 bytes para p75 y 1.093 bytes para p90
+ Figura 1. Distribución de bytes de JavaScript por página.
La Figura 1 anterior muestra que utilizamos 373 KB de JavaScript en el percentil 50, o mediana. En otras palabras, el 50% de todos los sitios envían más de este JavaScript a sus usuarios.
@@ -43,8 +43,8 @@ Mirando estos números, es natural preguntarse si esto es demasiado JavaScript.
-
Gráfico de barras que muestra 76 bytes / 65 bytes de JavaScript se usa en el percentil p10 en computadoras de escritorio y dispositivos móviles respectivamente, 186/164 bytes para p25, 391/359 bytes para p50, 721/668 bytes para p75 y 1.131 / 1.060 bytes para p90 .
- Figura 2. Distribución de JavaScript por página por dispositivo.
+
Gráfico de barras que muestra 76 bytes / 65 bytes de JavaScript se usa en el percentil p10 en computadoras de escritorio y dispositivos móviles respectivamente, 186/164 bytes para p25, 391/359 bytes para p50, 721/668 bytes para p75 y 1.131 / 1.060 bytes para p90 .
+ Figura 2. Distribución de JavaScript por página por dispositivo.
En cada percentil, estamos enviando un poco más de JavaScript a los dispositivos de escritorio que a los dispositivos móviles.
@@ -59,8 +59,8 @@ Podemos tener una idea analizando los tiempos de procesamiento de subprocesos pr
-
Gráfico de barras que muestra 141 ms / 377 ms de tiempo de procesamiento se utiliza en el percentil p10 en computadoras de escritorio y dispositivos móviles respectivamente, 352/988 ms para p25, 849 / 2.437 ms para p50, 1.850 / 5.518 ms para p75 y 3.543 / 10.735 ms para p90.
- Figura 3. Tiempos de procesamiento de subprocesos principales según V8 por dispositivo.
+
Gráfico de barras que muestra 141 ms / 377 ms de tiempo de procesamiento se utiliza en el percentil p10 en computadoras de escritorio y dispositivos móviles respectivamente, 352/988 ms para p25, 849 / 2.437 ms para p50, 1.850 / 5.518 ms para p75 y 3.543 / 10.735 ms para p90.
+ Figura 3. Tiempos de procesamiento de subprocesos principales según V8 por dispositivo.
En cada percentil, los tiempos de procesamiento son más largos para las páginas web móviles que para las computadoras de escritorio. La mediana del tiempo total de subprocesos principales en el escritorio es de 849 ms, mientras que el móvil está en un número mayor: 2.437 ms.
@@ -68,11 +68,11 @@ En cada percentil, los tiempos de procesamiento son más largos para las página
Aunque estos datos muestran cuánto tiempo puede llevar un dispositivo móvil procesar JavaScript en comparación con una máquina de escritorio más potente, los dispositivos móviles también varían en términos de potencia informática. El siguiente cuadro muestra cómo los tiempos de procesamiento en una sola página web pueden variar significativamente según la clase de dispositivo móvil.
### Número de Solicitudes
@@ -83,8 +83,8 @@ Una vía que vale la pena explorar al tratar de analizar la cantidad de JavaScri
-
Gráfico de barras que muestra 4/4 solicitudes se utilizan para computadoras de escritorio y dispositivos móviles respectivamente en el percentil p10, 10/9 en p25, 19/18 en p50, 33/32 en p75 y 53/52 en p90.
- Figura 5. Distribución del total de solicitudes de JavaScript.
+
Gráfico de barras que muestra 4/4 solicitudes se utilizan para computadoras de escritorio y dispositivos móviles respectivamente en el percentil p10, 10/9 en p25, 19/18 en p50, 33/32 en p75 y 53/52 en p90.
+ Figura 5. Distribución del total de solicitudes de JavaScript.
En la mediana, se envían 19 solicitudes para computadoras de escritorio y 18 para dispositivos móviles.
@@ -99,16 +99,16 @@ JavaScript de contenido de terceros puede provenir de cualquier fuente externa d
-
Gráfico de barras que muestra las solicitudes 0/1 en el escritorio es contenido de origen y contenido de terceros, respectivamente, en el percentil p10, 2/4 en la p25, 6/10 en la p50, 13/21 en la p75 y 24/38 en la p90.
- Figura 6. Distribución de scripts de origen y de terceros en dispositivos de escritorio.
+
Gráfico de barras que muestra las solicitudes 0/1 en el escritorio es contenido de origen y contenido de terceros, respectivamente, en el percentil p10, 2/4 en la p25, 6/10 en la p50, 13/21 en la p75 y 24/38 en la p90.
+ Figura 6. Distribución de scripts de origen y de terceros en dispositivos de escritorio.
Para clientes móviles y de escritorio, se envían más solicitudes de contenido de terceros que de contenido de origen en cada percentil. Si esto parece sorprendente, descubramos cuánto código real enviado proviene de proveedores externos.
@@ -117,16 +117,16 @@ Para clientes móviles y de escritorio, se envían más solicitudes de contenido
-
Gráfico de barras que muestra 0/17 bytes de JavaScript se descarga en dispositivos de escritorio para contenido de origen y contenido de terceros, respectivamente, en el percentil p10, 11/62 en p25, 89/232 en p50, 200/525 en p75 y 404/900 en p90.
- Figura 8. Distribución del JavaScript total descargado en dispositivos de escritorio.
+
Gráfico de barras que muestra 0/17 bytes de JavaScript se descarga en dispositivos de escritorio para contenido de origen y contenido de terceros, respectivamente, en el percentil p10, 11/62 en p25, 89/232 en p50, 200/525 en p75 y 404/900 en p90.
+ Figura 8. Distribución del JavaScript total descargado en dispositivos de escritorio.
En la mediana, se utiliza un 89% más de código de contenido de terceros que el código de contenido de origen creado por el desarrollador para dispositivos móviles y de escritorio. Esto muestra claramente que el código de terceros puede ser uno de los mayores contribuyentes a la inflación.
@@ -148,8 +148,8 @@ Los scripts comprimidos siempre deberán ser descomprimidos por el navegador una
-
Gráfico de barras que muestra el 67% / 65% de los recursos de JavaScript se comprime con gzip en computadoras de escritorio y dispositivos móviles respectivamente, y el 15% / 14% se comprime con Brotli.
- Figura 10. Porcentaje de sitios que comprimen recursos de JavaScript con gzip o brotli.
+
Gráfico de barras que muestra el 67% / 65% de los recursos de JavaScript se comprime con gzip en computadoras de escritorio y dispositivos móviles respectivamente, y el 15% / 14% se comprime con Brotli.
+ Figura 10. Porcentaje de sitios que comprimen recursos de JavaScript con gzip o brotli.
La mayoría de los sitios están comprimiendo sus recursos de JavaScript. La codificación Gzip se usa en ~ 64-67% de los sitios y Brotli en ~ 14%. Las relaciones de compresión son similares tanto para computadoras de escritorio como para dispositivos móviles.
@@ -163,7 +163,7 @@ Código fuente abierto, o código con una licencia permisiva a la que cualquier
**¿Qué bibliotecas de código abierto de JavaScript se usan más?**
-
+
Librería
@@ -279,7 +279,7 @@ Código fuente abierto, o código con una licencia permisiva a la que cualquier
- Figura 11. Principales bibliotecas de JavaScript en computadoras de escritorio y dispositivos móviles.
+ Figura 11. Principales bibliotecas de JavaScript en computadoras de escritorio y dispositivos móviles.
[jQuery](https://jquery.com/), la biblioteca JavaScript más popular jamás creada, se utiliza en el 85,03% de las páginas de escritorio y el 83,46% de las páginas móviles. El advenimiento de muchas API y métodos del navegador, tales como [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) y [querySelector](https://developer.mozilla.org/docs/Web/API/Document/querySelector), estandarizaron gran parte de la funcionalidad proporcionada por la biblioteca en una forma nativa. Aunque la popularidad de jQuery puede parecer estar disminuyendo, ¿por qué todavía se usa en la gran mayoría de la web?
@@ -301,8 +301,8 @@ En los últimos años, el ecosistema de JavaScript ha visto un aumento en las bi
-
Gráfico de barras que muestra que el 4,6% de los sitios usan React, 2,0% AngiularJS, 1,8% Backbone.js, 0,8% Vue.js, 0,4% Knockout.js, 0,3% Zone.js, 0,3% Angular, 0,1% AMP, 0,1% Ember. js.
- Figura 12. Los frameworks más utilizados en el escritorio.
+
Gráfico de barras que muestra que el 4,6% de los sitios usan React, 2,0% AngiularJS, 1,8% Backbone.js, 0,8% Vue.js, 0,4% Knockout.js, 0,3% Zone.js, 0,3% Angular, 0,1% AMP, 0,1% Ember. js.
+ Figura 12. Los frameworks más utilizados en el escritorio.
Aquí solo se analiza un subconjunto de marcos populares, pero es importante tener en cuenta que todos ellos siguen uno de estos dos enfoques:
@@ -330,8 +330,8 @@ Para declarar un script como módulo, la etiqueta del script debe tener el códi
-
Gráfico de barras que muestra el 0,6% de los sitios en computadoras de escritorio usan 'type=module' y el 0,8% de los sitios en dispositivos móviles.
- Figura 13. Porcentaje de sitios que utilizan type=module.
+
Gráfico de barras que muestra el 0,6% de los sitios en computadoras de escritorio usan 'type=module' y el 0,8% de los sitios en dispositivos móviles.
+ Figura 13. Porcentaje de sitios que utilizan type=module.
El soporte a nivel de navegador para módulos todavía es relativamente nuevo, y los números aquí muestran que muy pocos sitios usan actualmente `type="module"` para sus scripts. Muchos sitios todavía dependen de cargadores de módulos (2,37% de todos los sitios de escritorio usan [RequireJS](https://github.com/requirejs/requirejs) por ejemplo) y _bundlers_ ([webpack](https://webpack.js.org/) por ejemplo) para definir módulos dentro de su código fuente.
@@ -350,8 +350,8 @@ Así que, **¿Cuántos sitios usan `nomodule` para los scripts en su página?**
-
Gráfico de barras que muestra el 0,8% de los sitios en computadoras de escritorio usan 'nomodule' y el 0,5% de los sitios en dispositivos móviles.
- Figura 14. Porcentaje de sitios que usan nomodule.
+
Gráfico de barras que muestra el 0,8% de los sitios en computadoras de escritorio usan 'nomodule' y el 0,5% de los sitios en dispositivos móviles.
+ Figura 14. Porcentaje de sitios que usan nomodule.
Del mismo modo, muy pocos sitios (0,50% - 0,80%) usan el atributo `nomodule` para cualquier script.
@@ -369,8 +369,8 @@ Del mismo modo, muy pocos sitios (0,50% - 0,80%) usan el atributo `nomodule` par
-
Gráfico de barras que muestra que el 14% de los sitios en computadoras de escritorio usan 'rel=preload 'para scripts, y el 15% de los sitios en dispositivos móviles.
- Figura 15. Porcentaje de sitios que usan rel=preload para scripts.
+
Gráfico de barras que muestra que el 14% de los sitios en computadoras de escritorio usan 'rel=preload 'para scripts, y el 15% de los sitios en dispositivos móviles.
+ Figura 15. Porcentaje de sitios que usan rel=preload para scripts.
Para todos los sitios medidos en HTTP Archive, el 14.33% de los sitios de computadoras de escritorio y el 14.84% de los sitios en dispositivos móviles usan `` para los scripts en su página.
@@ -381,8 +381,8 @@ Para _prefetch_:
-
Gráfico de barras que muestra el 0,08% de los sitios en computadoras de escritorio usan 'rel=prefetch' y el 0,08% de los sitios en dispositivos móviles.
- Figura 16. Porcentaje de sitios que usan rel=prefetch para scripts.
+
Gráfico de barras que muestra el 0,08% de los sitios en computadoras de escritorio usan 'rel=prefetch' y el 0,08% de los sitios en dispositivos móviles.
+ Figura 16. Porcentaje de sitios que usan rel=prefetch para scripts.
Tanto para dispositivos móviles como para computadoras de escritorio, el 0,08% de las páginas aprovechan la captación previa para cualquiera de sus scripts.
@@ -406,8 +406,8 @@ Con HTTP Archive, podemos echar un vistazo a cualquier API más nueva que sea co
-
Gráfico de barras que muestra el 25,5% / 36,2% de los sitios en computadoras de escritorio y dispositivos móviles usa WeakMap, 6,1% / 17,2% usa WeakSet, 3,9% / 14,0% usa Intl, 3,9% / 4,4% usa Proxy, 0,4% / 0,4% usa Atomics, y 0,2% / 0,2% usan SharedArrayBuffer.
- Figura 17. Uso de nuevas API de JavaScript.
+
Gráfico de barras que muestra el 25,5% / 36,2% de los sitios en computadoras de escritorio y dispositivos móviles usa WeakMap, 6,1% / 17,2% usa WeakSet, 3,9% / 14,0% usa Intl, 3,9% / 4,4% usa Proxy, 0,4% / 0,4% usa Atomics, y 0,2% / 0,2% usan SharedArrayBuffer.
+ Figura 17. Uso de nuevas API de JavaScript.
Atomics (0,38%) y SharedArrayBuffer (0,20%) son apenas visibles en este gráfico ya que se usan en tan pocas páginas.
@@ -426,8 +426,8 @@ Aunque es útil, hay una serie de razones por las cuales muchos sitios pueden no
-
Gráfico de barras que muestra el 18% de los sitios de escritorio y el 17% de los sitios móviles utilizan mapas fuente.
- Figura 18. Porcentaje de sitios que usan mapas fuente.
+
Gráfico de barras que muestra el 18% de los sitios de escritorio y el 17% de los sitios móviles utilizan mapas fuente.
+ Figura 18. Porcentaje de sitios que usan mapas fuente.
Para las páginas de escritorio y móviles, los resultados son casi los mismos. Un 17-18% incluye un mapa fuente para al menos un script en la página (detectado como un script de contenido de origen con `sourceMappingURL`).
diff --git a/src/content/es/2019/performance.md b/src/content/es/2019/performance.md
index 5b75dba424f..c20b81ddd31 100644
--- a/src/content/es/2019/performance.md
+++ b/src/content/es/2019/performance.md
@@ -17,7 +17,7 @@ last_updated: 2020-03-01T00:00:00.000Z
El rendimiento es una parte esencial de la experiencia del usuario. En [muchos sitios web](https://wpostats.com/), una mejora en la experiencia del usuario al acelerar el tiempo de carga de la página se corresponde con una mejora en las tasas de conversión. Por el contrario, cuando el rendimiento es deficiente, los usuarios no realizan conversiones con tanta frecuencia e incluso se ha observado que realizan [ráfagas de clicks](https://blog.fullstory.com/rage-clicks-turn-analytics-into-actionable-insights/) en la página como muestra de frustración.
-Hay muchas formas de cuantificar el rendimiento web. Lo más importante es medir lo que realmente importa a los usuarios. Eventos como `onload` o` DOMContentLoaded` pueden no reflejar necesariamente lo que los usuarios experimentan visualmente. Por ejemplo, al cargar un cliente de correo electrónico, puede mostrar una barra de progreso mientras el contenido de la bandeja de entrada se carga de forma asincróna. El problema es que el evento `onload` no espera a que la bandeja de entrada se cargue asincrónamente. En este ejemplo, la métrica de carga que más le importa a los usuarios es el "tiempo para la bandeja de entrada", y centrarse en el evento `onload` puede ser engañoso. Por esa razón, este capítulo analizará métricas de pintado, carga e interactividad más modernas y de aplicación universal para tratar de capturar cómo los usuarios realmente están experimentando la página.
+Hay muchas formas de cuantificar el rendimiento web. Lo más importante es medir lo que realmente importa a los usuarios. Eventos como `onload` o `DOMContentLoaded` pueden no reflejar necesariamente lo que los usuarios experimentan visualmente. Por ejemplo, al cargar un cliente de correo electrónico, puede mostrar una barra de progreso mientras el contenido de la bandeja de entrada se carga de forma asincróna. El problema es que el evento `onload` no espera a que la bandeja de entrada se cargue asincrónamente. En este ejemplo, la métrica de carga que más le importa a los usuarios es el "tiempo para la bandeja de entrada", y centrarse en el evento `onload` puede ser engañoso. Por esa razón, este capítulo analizará métricas de pintado, carga e interactividad más modernas y de aplicación universal para tratar de capturar cómo los usuarios realmente están experimentando la página.
Hay dos tipos de datos de rendimiento: laboratorio y campo. También se les denomina pruebas sintéticas y medidas de usuario real (real-user measurement o RUM). La medición del rendimiento en el laboratorio garantiza que cada sitio web se pruebe bajo condiciones comunes y las variables como el navegador, la velocidad de conexión, la ubicación física, el estado de la memoria caché, etc., permanecen iguales. Esta garantía de consistencia hace que cada sitio web sea comparable entre sí. Por otro lado, medir el rendimiento en el campo representa cómo los usuarios realmente experimentan la web en todas las combinaciones infinitas de condiciones que nunca podríamos capturar en el laboratorio. Para los propósitos de este capítulo y para comprender las experiencias de los usuarios del mundo real, nos centraremos en los datos de campo.
@@ -139,7 +139,7 @@ Otros geos de APAC cuentan una historia diferente. Tailandia, Vietnam, Indonesia
Figura 8. Diagrama de la API de Navigation Timing de los eventos en la navegación de una página.
-Para ayudar a explicar TTFB y los muchos factores que lo afectan, tomemos prestado un diagrama de la [especificación de la API de Navigation Timing](https://developer.mozilla.org/docs/Web/API/Navigation_timing_API). En la Figura 8 anterior, TTFB es la duración desde `startTime` hasta` responseStart`, que incluye todo lo que se encuentra entre: `unload`, `redirects`, `AppCache`,` DNS`, `SSL`,` TCP` y el tiempo el servidor pasa gestionando la petición. Dado ese contexto, veamos cómo los usuarios están experimentando esta métrica.
+Para ayudar a explicar TTFB y los muchos factores que lo afectan, tomemos prestado un diagrama de la [especificación de la API de Navigation Timing](https://developer.mozilla.org/docs/Web/API/Navigation_timing_API). En la Figura 8 anterior, TTFB es la duración desde `startTime` hasta `responseStart`, que incluye todo lo que se encuentra entre: `unload`, `redirects`, `AppCache`, `DNS`, `SSL`, `TCP` y el tiempo el servidor pasa gestionando la petición. Dado ese contexto, veamos cómo los usuarios están experimentando esta métrica.
すべてのパーセンタイルにおいて、処理時間はデスクトップよりもモバイルの方が長くなっています。メインスレッドの合計時間の中央値はデスクトップでは849msであるのに対し、モバイルでは2,437msと大きくなっています。
@@ -68,11 +68,11 @@ V8のメインスレッドの処理時間を異なるパーセンタイルで分
このデータはモバイルデバイスがJavaScriptを処理するのにかかる時間が、より強力なデスクトップマシンに比べてどれだけ長いかを示していますが、モバイルデバイスは計算能力の点でも違いがあります。次の表は、1つのWebページの処理時間がモバイルデバイスのクラスによって大きく異なることを示しています。
-
-
-
-