1131 lines
139 KiB
HTML
1131 lines
139 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en-US" id="hacks-mozilla-org">
|
||
|
||
<head>
|
||
<meta name="viewport" content="width=device-width">
|
||
<meta charset="UTF-8">
|
||
<!-- OpenGraph metadata -->
|
||
<meta property="og:site_name" content="Mozilla Hacks – the Web developer blog">
|
||
<meta property="og:title" content="This API is so Fetching!">
|
||
<meta property="og:url" content="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/">
|
||
<meta property="og:description" content="For more than a decade the Web has used XMLHttpRequest (XHR) to achieve asynchronous requests in JavaScript. While very useful, XHR is not a very ...">
|
||
<!--[if IE]>
|
||
<meta name="MSSmartTagsPreventParsing" content="true">
|
||
<meta http-equiv="imagetoolbar" content="no">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||
<script src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||
<![endif]-->
|
||
<link rel="shortcut icon" type="image/ico" href="https://hacks.mozilla.org/wp-content/themes/Hacks2013/favicon.ico">
|
||
<link rel="home" href="/">
|
||
<link rel="copyright" href="#copyright">
|
||
<link rel="stylesheet" type="text/css" media="screen,projection" href="https://hacks.mozilla.org/wp-content/themes/Hacks2013/style.css">
|
||
<link rel="stylesheet" type="text/css" media="print,handheld" href="https://hacks.mozilla.org/wp-content/themes/Hacks2013/css/print.css">
|
||
<link rel="stylesheet" type="text/css" media="all" href="https://www.mozilla.org/tabzilla/media/css/tabzilla.css">
|
||
<link rel="stylesheet" type="text/css" media="all" href="https://hacks.mozilla.org/wp-content/themes/Hacks2013/css/socialshare.css">
|
||
<link rel="alternate" type="application/rss+xml" title="Mozilla Hacks – the Web developer blog RSS Feed"
|
||
href="https://hacks.mozilla.org/feed/">
|
||
<link rel="pingback" href="https://hacks.mozilla.org/xmlrpc.php">
|
||
<link rel="canonical" href="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/">
|
||
<!--[if lte IE 7]>
|
||
<link rel="stylesheet" type="text/css" media="all" href="https://hacks.mozilla.org/wp-content/themes/Hacks2013/css/ie7.css"
|
||
/>
|
||
<![endif]-->
|
||
<!--[if lte IE 6]>
|
||
<link rel="stylesheet" type="text/css" media="all" href="https://hacks.mozilla.org/wp-content/themes/Hacks2013/css/ie6.css"
|
||
/>
|
||
<![endif]-->
|
||
<title>This API is so Fetching! ✩ Mozilla Hacks – the Web developer blog</title>
|
||
<script
|
||
type="text/javascript">window.hacks = {}; // http://cfsimplicity.com/61/removing-analytics-clutter-from-campaign-urls
|
||
var removeUtms = function(){ var l = window.location; if( l.hash.indexOf(
|
||
"utm" ) != -1 ){ var anchor = l.hash.match(/#(?!utm)[^&]+/); anchor = anchor?
|
||
anchor[0]: ''; if(!anchor && window.history.replaceState){ history.replaceState({},'',
|
||
l.pathname + l.search); } else { l.hash = anchor; } }; }; var _gaq = _gaq
|
||
|| []; _gaq.push(['_setAccount', 'UA-35433268-8'], ['_setAllowAnchor',
|
||
true]); _gaq.push (['_gat._anonymizeIp']); _gaq.push(['_trackPageview']);
|
||
_gaq.push( removeUtms ); (function(d, k) { var ga = d.createElement(k);
|
||
ga.type = 'text/javascript'; ga.async = true; ga.src = 'https://ssl.google-analytics.com/ga.js';
|
||
var s = d.getElementsByTagName(k)[0]; s.parentNode.insertBefore(ga, s);
|
||
})(document, 'script');</script>
|
||
<link rel="alternate" type="application/rss+xml"
|
||
title="Mozilla Hacks - the Web developer blog » This API is so Fetching! Comments Feed"
|
||
href="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/feed/">
|
||
<link rel="stylesheet" id="wp-syntax-css-css" href="https://hacks.mozilla.org/wp-content/plugins/wp-syntax/css/wp-syntax.css?ver=1.0"
|
||
type="text/css" media="all">
|
||
<script type="text/javascript" src="https://hacks.mozilla.org/wp-includes/js/jquery/jquery.js?ver=1.11.1"></script>
|
||
<script type="text/javascript" src="https://hacks.mozilla.org/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1"></script>
|
||
<script type="text/javascript" src="https://hacks.mozilla.org/wp-content/themes/Hacks2013/js/fc-checkcomment.js?ver=4.1"></script>
|
||
<script type="text/javascript" src="https://hacks.mozilla.org/wp-content/themes/Hacks2013/js/analytics.js?ver=4.1"></script>
|
||
<script type="text/javascript" src="https://hacks.mozilla.org/wp-content/themes/Hacks2013/js/socialshare.min.js?ver=4.1"></script>
|
||
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://hacks.mozilla.org/xmlrpc.php?rsd">
|
||
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://hacks.mozilla.org/wp-includes/wlwmanifest.xml">
|
||
<link rel="prev" title="Ruby support in Firefox Developer Edition 38"
|
||
href="https://hacks.mozilla.org/2015/03/ruby-support-in-firefox-developer-edition-38/">
|
||
<link rel="next" title="Optimising SVG images" href="https://hacks.mozilla.org/2015/03/optimising-svg-images/">
|
||
<link rel="canonical" href="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/">
|
||
<link rel="shortlink" href="https://hacks.mozilla.org/?p=28260">
|
||
<script type="text/javascript">
|
||
var _gaq = _gaq || [];
|
||
_gaq.push(['_setAccount', 'UA-36116321-4']);
|
||
_gaq.push(['_trackPageview']);
|
||
|
||
(function() {
|
||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||
})();
|
||
</script>
|
||
</head>
|
||
|
||
<body class="single single-post postid-28260 single-format-standard">
|
||
<div id="outer-wrapper">
|
||
<ul id="nav-access" role="navigation">
|
||
<li><a href="#content-main">Skip to content</a>
|
||
</li>
|
||
</ul>
|
||
<header id="branding">
|
||
<h4 id="logo">hacks.mozilla.org <a href="https://hacks.mozilla.org" title="Go to the home page">Home</a></h4>
|
||
|
||
<form id="fm-search" method="get" action="https://hacks.mozilla.org/"
|
||
role="search">
|
||
<p>
|
||
<input type="search" placeholder="Search hacks.mozilla.org" value="" name="s"
|
||
id="s">
|
||
<button type="submit">Go</button>
|
||
</p>
|
||
</form>
|
||
<nav id="nav-main">
|
||
<ul role="navigation">
|
||
<li><a href="https://hacks.mozilla.org">Home</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/articles/">Articles</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/demos/">Demos</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/about/">About</a>
|
||
</li>
|
||
</ul>
|
||
</nav> <a href="#" id="tabzilla">Mozilla</a>
|
||
|
||
</header>
|
||
<!-- /#branding -->
|
||
<div id="content">
|
||
<div id="content-head">
|
||
<ul class="nav-crumbs">
|
||
<li><a href="https://hacks.mozilla.org" title="Go to the home page">Home</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/articles/">Articles</a>
|
||
</li>
|
||
</ul>
|
||
<h1 class="page-title">This API is so Fetching!</h1>
|
||
|
||
<ul class="nav-paging">
|
||
<li class="prev"><a href="https://hacks.mozilla.org/2015/03/ruby-support-in-firefox-developer-edition-38/"
|
||
rel="prev">Older Article</a>
|
||
</li>
|
||
<li class="next"><a href="https://hacks.mozilla.org/2015/03/optimising-svg-images/" rel="next">Newer Article</a>
|
||
</li>
|
||
</ul>
|
||
<div id="content-bar" class="single">
|
||
<div class="entry-meta">
|
||
<p class="entry-posted">on <abbr class="published" title="2015-03-10T08:05:41-07:00">March 10, 2015</abbr>
|
||
by
|
||
<a
|
||
href="https://hacks.mozilla.org/author/nmarathemozilla-com/" title="Posts by Nikhil Marathe"
|
||
class="url fn" rel="author">Nikhil Marathe</a>
|
||
</p>
|
||
<p class="entry-cat">in <a href="https://hacks.mozilla.org/category/featured/" rel="category tag">Featured Article</a>
|
||
<a
|
||
href="https://hacks.mozilla.org/category/serviceworkers/" rel="category tag">ServiceWorkers</a> <a href="https://hacks.mozilla.org/category/web-workers/"
|
||
rel="category tag">Web Workers</a> <a href="https://hacks.mozilla.org/category/webapi/"
|
||
rel="category tag">WebAPI</a>
|
||
</p>
|
||
</div>
|
||
<ul class="entry-extra">
|
||
<li class="comments"> <a href="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/#comments">2 comments</a>
|
||
|
||
</li>
|
||
<li class="share">
|
||
<div class="socialshare" data-type="small-bubbles"></div>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<!-- /#content-head -->
|
||
<main id="content-main" class="hfeed">
|
||
<article class="post" role="article">
|
||
<p>For more than a decade the Web has used XMLHttpRequest (XHR) to achieve
|
||
asynchronous requests in JavaScript. While very useful, XHR is not a very
|
||
nice API. It suffers from lack of separation of concerns. The input, output
|
||
and state are all managed by interacting with one object, and state is
|
||
tracked using events. Also, the event-based model doesn’t play well with
|
||
JavaScript’s recent focus on Promise- and generator-based asynchronous
|
||
programming.</p>
|
||
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a> intends
|
||
to fix most of these problems. It does this by introducing the same primitives
|
||
to JS that are used in the HTTP protocol. In addition, it introduces a
|
||
utility function <code>fetch()</code> that succinctly captures the intention
|
||
of retrieving a resource from the network.</p>
|
||
<p>The <a href="https://fetch.spec.whatwg.org">Fetch specification</a>, which
|
||
defines the API, nails down the semantics of a user agent fetching a resource.
|
||
This, combined with ServiceWorkers, is an attempt to:</p>
|
||
<ol>
|
||
<li>Improve the offline experience.</li>
|
||
<li>Expose the building blocks of the Web to the platform as part of the
|
||
<a
|
||
href="https://extensiblewebmanifesto.org/">extensible web movement</a>.</li>
|
||
</ol>
|
||
<p>As of this writing, the Fetch API is available in Firefox 39 (currently
|
||
Nightly) and Chrome 42 (currently dev). Github has a <a href="https://github.com/github/fetch">Fetch polyfill</a>.</p>
|
||
|
||
<h2>Feature detection</h2>
|
||
|
||
<p>Fetch API support can be detected by checking for <code>Headers</code>,<code>Request</code>, <code>Response</code> or <code>fetch</code> on
|
||
the <code>window</code> or <code>worker</code> scope.</p>
|
||
|
||
<h2>Simple fetching</h2>
|
||
|
||
<p>The most useful, high-level part of the Fetch API is the <code>fetch()</code> function.
|
||
In its simplest form it takes a URL and returns a promise that resolves
|
||
to the response. The response is captured as a <code>Response</code> object.</p>
|
||
<div
|
||
class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">fetch<span style="color: #009900;">(</span><span style="color: #3366CC;">"/data.json"</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>res<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #006600; font-style: italic;">// res instanceof Response == true.</span>
|
||
<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">(</span>res.<span style="color: #660066;">ok</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
res.<span style="color: #660066;">json</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>data<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>data.<span style="color: #660066;">entries</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Looks like the response wasn't perfect, got status"</span><span style="color: #339933;">,</span> res.<span style="color: #660066;">status</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span>
|
||
<span style="color: #009900;">}</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>e<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Fetch failed!"</span><span style="color: #339933;">,</span> e<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>Submitting some parameters, it would look like this:</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">fetch<span style="color: #009900;">(</span><span style="color: #3366CC;">"http://www.example.org/submit.php"</span><span style="color: #339933;">,</span> <span style="color: #009900;">{</span>
|
||
method<span style="color: #339933;">:</span> <span style="color: #3366CC;">"POST"</span><span style="color: #339933;">,</span>
|
||
headers<span style="color: #339933;">:</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #3366CC;">"Content-Type"</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">"application/x-www-form-urlencoded"</span>
|
||
<span style="color: #009900;">}</span><span style="color: #339933;">,</span>
|
||
body<span style="color: #339933;">:</span> <span style="color: #3366CC;">"firstName=Nikhil&favColor=blue&password=easytoguess"</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>res<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">(</span>res.<span style="color: #660066;">ok</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
alert<span style="color: #009900;">(</span><span style="color: #3366CC;">"Perfect! Your settings are saved."</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">(</span>res.<span style="color: #660066;">status</span> <span style="color: #339933;">==</span> <span style="color: #CC0000;">401</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
alert<span style="color: #009900;">(</span><span style="color: #3366CC;">"Oops! You are not authorized."</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span>
|
||
<span style="color: #009900;">}</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>e<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
alert<span style="color: #009900;">(</span><span style="color: #3366CC;">"Error submitting form!"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>The <code>fetch()</code> function’s arguments are the same as those passed
|
||
to the
|
||
<br>
|
||
<code>Request()</code> constructor, so you may directly pass arbitrarily
|
||
complex requests to <code>fetch()</code> as discussed below.</p>
|
||
|
||
<h2>Headers</h2>
|
||
|
||
<p>Fetch introduces 3 interfaces. These are <code>Headers</code>, <code>Request</code> and
|
||
<br>
|
||
<code>Response</code>. They map directly to the underlying HTTP concepts,
|
||
but have
|
||
<br>certain visibility filters in place for privacy and security reasons,
|
||
such as
|
||
<br>supporting CORS rules and ensuring cookies aren’t readable by third parties.</p>
|
||
<p>The <a href="https://fetch.spec.whatwg.org/#headers-class">Headers interface</a> is
|
||
a simple multi-map of names to values:</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> content <span style="color: #339933;">=</span> <span style="color: #3366CC;">"Hello World"</span><span style="color: #339933;">;</span>
|
||
<span style="color: #000066; font-weight: bold;">var</span> reqHeaders <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Headers<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
reqHeaders.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Content-Type"</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"text/plain"</span>
|
||
reqHeaders.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Content-Length"</span><span style="color: #339933;">,</span> content.<span style="color: #660066;">length</span>.<span style="color: #660066;">toString</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
reqHeaders.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"X-Custom-Header"</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"ProcessThisImmediately"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>The same can be achieved by passing an array of arrays or a JS object
|
||
literal
|
||
<br>to the constructor:</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">reqHeaders <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Headers<span style="color: #009900;">(</span><span style="color: #009900;">{</span>
|
||
<span style="color: #3366CC;">"Content-Type"</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">"text/plain"</span><span style="color: #339933;">,</span>
|
||
<span style="color: #3366CC;">"Content-Length"</span><span style="color: #339933;">:</span> content.<span style="color: #660066;">length</span>.<span style="color: #660066;">toString</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">,</span>
|
||
<span style="color: #3366CC;">"X-Custom-Header"</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">"ProcessThisImmediately"</span><span style="color: #339933;">,</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>The contents can be queried and retrieved:</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>reqHeaders.<span style="color: #660066;">has</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Content-Type"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// true</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>reqHeaders.<span style="color: #660066;">has</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Set-Cookie"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// false</span>
|
||
reqHeaders.<span style="color: #000066; font-weight: bold;">set</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Content-Type"</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"text/html"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
reqHeaders.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"X-Custom-Header"</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"AnotherValue"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>reqHeaders.<span style="color: #000066; font-weight: bold;">get</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Content-Length"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// 11</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>reqHeaders.<span style="color: #660066;">getAll</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"X-Custom-Header"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// ["ProcessThisImmediately", "AnotherValue"]</span>
|
||
|
||
reqHeaders.<span style="color: #000066; font-weight: bold;">delete</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"X-Custom-Header"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>reqHeaders.<span style="color: #660066;">getAll</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"X-Custom-Header"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// []</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>Some of these operations are only useful in ServiceWorkers, but they provide
|
||
<br>a much nicer API to Headers.</p>
|
||
<p>Since Headers can be sent in requests, or received in responses, and have
|
||
various limitations about what information can and should be mutable, <code>Headers</code> objects
|
||
have a <strong>guard</strong> property. This is not exposed to the Web, but
|
||
it affects which mutation operations are allowed on the Headers object.
|
||
<br>Possible values are:</p>
|
||
<ul>
|
||
<li>“none”: default.</li>
|
||
<li>“request”: guard for a Headers object obtained from a Request (<code>Request.headers</code>).</li>
|
||
<li>“request-no-cors”: guard for a Headers object obtained from a Request
|
||
created
|
||
<br>with mode “no-cors”.</li>
|
||
<li>“response”: naturally, for Headers obtained from Response (<code>Response.headers</code>).</li>
|
||
<li>“immutable”: Mostly used for ServiceWorkers, renders a Headers object
|
||
<br>read-only.</li>
|
||
</ul>
|
||
<p>The details of how each guard affects the behaviors of the Headers object
|
||
are
|
||
<br>in the <a href="https://fetch.spec.whatwg.org">specification</a>. For example,
|
||
you may not append or set a “request” guarded Headers’ “Content-Length”
|
||
header. Similarly, inserting “Set-Cookie” into a Response header is not
|
||
allowed so that ServiceWorkers may not set cookies via synthesized Responses.</p>
|
||
<p>All of the Headers methods throw TypeError if <code>name</code> is not a
|
||
<a
|
||
href="https://fetch.spec.whatwg.org/#concept-header-name">valid HTTP Header name</a>. The mutation operations will throw TypeError
|
||
if there is an immutable guard. Otherwise they fail silently. For example:</p>
|
||
<div
|
||
class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> res <span style="color: #339933;">=</span> Response.<span style="color: #660066;">error</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #000066; font-weight: bold;">try</span> <span style="color: #009900;">{</span>
|
||
res.<span style="color: #660066;">headers</span>.<span style="color: #000066; font-weight: bold;">set</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Origin"</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"http://mybank.com"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span> <span style="color: #000066; font-weight: bold;">catch</span><span style="color: #009900;">(</span>e<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Cannot pretend to be a bank!"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h2>Request</h2>
|
||
|
||
<p>The Request interface defines a request to fetch a resource over HTTP.
|
||
URL, method and headers are expected, but the Request also allows specifying
|
||
a body, a request mode, credentials and cache hints.</p>
|
||
<p>The simplest Request is of course, just a URL, as you may do to GET a
|
||
resource.</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> req <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Request<span style="color: #009900;">(</span><span style="color: #3366CC;">"/index.html"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>req.<span style="color: #660066;">method</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// "GET"</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>req.<span style="color: #660066;">url</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// "http://example.com/index.html"</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>You may also pass a Request to the <code>Request()</code> constructor to
|
||
create a copy.
|
||
<br>(This is not the same as calling the <code>clone()</code> method, which
|
||
is covered in
|
||
<br>the “Reading bodies” section.).</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> copy <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Request<span style="color: #009900;">(</span>req<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>copy.<span style="color: #660066;">method</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// "GET"</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>copy.<span style="color: #660066;">url</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// "http://example.com/index.html"</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>Again, this form is probably only useful in ServiceWorkers.</p>
|
||
<p>The non-URL attributes of the <code>Request</code> can only be set by passing
|
||
initial
|
||
<br>values as a second argument to the constructor. This argument is a dictionary.</p>
|
||
<div
|
||
class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> uploadReq <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Request<span style="color: #009900;">(</span><span style="color: #3366CC;">"/uploadImage"</span><span style="color: #339933;">,</span> <span style="color: #009900;">{</span>
|
||
method<span style="color: #339933;">:</span> <span style="color: #3366CC;">"POST"</span><span style="color: #339933;">,</span>
|
||
headers<span style="color: #339933;">:</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #3366CC;">"Content-Type"</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">"image/png"</span><span style="color: #339933;">,</span>
|
||
<span style="color: #009900;">}</span><span style="color: #339933;">,</span>
|
||
body<span style="color: #339933;">:</span> <span style="color: #3366CC;">"image data"</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>The Request’s mode is used to determine if cross-origin requests lead
|
||
to valid responses, and which properties on the response are readable.
|
||
Legal mode values are <code>"same-origin"</code>, <code>"no-cors"</code> (default)
|
||
and <code>"cors"</code>.</p>
|
||
<p>The <code>"same-origin"</code> mode is simple, if a request is made to another
|
||
origin with this mode set, the result is simply an error. You could use
|
||
this to ensure that
|
||
<br>a request is always being made to your origin.</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> arbitraryUrl <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"url-input"</span><span style="color: #009900;">)</span>.<span style="color: #660066;">value</span><span style="color: #339933;">;</span>
|
||
fetch<span style="color: #009900;">(</span>arbitraryUrl<span style="color: #339933;">,</span> <span style="color: #009900;">{</span> mode<span style="color: #339933;">:</span> <span style="color: #3366CC;">"same-origin"</span> <span style="color: #009900;">}</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>res<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Response succeeded?"</span><span style="color: #339933;">,</span> res.<span style="color: #660066;">ok</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>e<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Please enter a same-origin URL!"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>The <code>"no-cors"</code> mode captures what the web platform does by default
|
||
for scripts you import from CDNs, images hosted on other domains, and so
|
||
on. First, it prevents the method from being anything other than “HEAD”,
|
||
“GET” or “POST”. Second, if any ServiceWorkers intercept these requests,
|
||
they may not add or override any headers except for <a href="https://fetch.spec.whatwg.org/#simple-header">these</a>.
|
||
Third, JavaScript may not access any properties of the resulting Response.
|
||
This ensures that ServiceWorkers do not affect the semantics of the Web
|
||
and prevents security and privacy issues that could arise from leaking
|
||
data across domains.</p>
|
||
<p><code>"cors"</code> mode is what you’ll usually use to make known cross-origin
|
||
requests to access various APIs offered by other vendors. These are expected
|
||
to adhere to
|
||
<br>the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS">CORS protocol</a>.
|
||
Only a <a href="https://fetch.spec.whatwg.org/#concept-filtered-response-cors">limited set</a> of
|
||
headers is exposed in the Response, but the body is readable. For example,
|
||
you could get a list of Flickr’s <a href="https://www.flickr.com/services/api/flickr.interestingness.getList.html">most interesting</a> photos
|
||
today like this:</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> u <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> URLSearchParams<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
u.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">'method'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'flickr.interestingness.getList'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
u.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">'api_key'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'<insert api key here>'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
u.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">'format'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'json'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
u.<span style="color: #660066;">append</span><span style="color: #009900;">(</span><span style="color: #3366CC;">'nojsoncallback'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'1'</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
|
||
<span style="color: #000066; font-weight: bold;">var</span> apiCall <span style="color: #339933;">=</span> fetch<span style="color: #009900;">(</span><span style="color: #3366CC;">'https://api.flickr.com/services/rest?'</span> <span style="color: #339933;">+</span> u<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
|
||
apiCall.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>response<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #000066; font-weight: bold;">return</span> response.<span style="color: #660066;">json</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>json<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #006600; font-style: italic;">// photo is a list of photos.</span>
|
||
<span style="color: #000066; font-weight: bold;">return</span> json.<span style="color: #660066;">photos</span>.<span style="color: #660066;">photo</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>photos<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
photos.<span style="color: #660066;">forEach</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>photo<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>photo.<span style="color: #660066;">title</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>You may not read out the “Date” header since Flickr does not allow it
|
||
via
|
||
<br>
|
||
<code>Access-Control-Expose-Headers</code>.</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">response.<span style="color: #660066;">headers</span>.<span style="color: #000066; font-weight: bold;">get</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Date"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// null</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>The <code>credentials</code> enumeration determines if cookies for the other
|
||
domain are
|
||
<br>sent to cross-origin requests. This is similar to XHR’s <code>withCredentials</code>
|
||
<br>flag, but tri-valued as <code>"omit"</code> (default), <code>"same-origin"</code> and <code>"include"</code>.</p>
|
||
<p>The Request object will also give the ability to offer caching hints to
|
||
the user-agent. This is currently undergoing some <a href="https://github.com/slightlyoff/ServiceWorker/issues/585">security review</a>.
|
||
Firefox exposes the attribute, but it has no effect.</p>
|
||
<p>Requests have two read-only attributes that are relevant to ServiceWorkers
|
||
<br>intercepting them. There is the string <code>referrer</code>, which is
|
||
set by the UA to be
|
||
<br>the referrer of the Request. This may be an empty string. The other is
|
||
<br>
|
||
<code>context</code> which is a rather <a href="https://fetch.spec.whatwg.org/#requestcredentials">large enumeration</a> defining
|
||
what sort of resource is being fetched. This could be “image” if the request
|
||
is from an
|
||
<img>tag in the controlled document, “worker” if it is an attempt to load a
|
||
worker script, and so on. When used with the <code>fetch()</code> function,
|
||
it is “fetch”.</p>
|
||
|
||
<h2>Response</h2>
|
||
|
||
<p><code>Response</code> instances are returned by calls to <code>fetch()</code>.
|
||
They can also be created by JS, but this is only useful in ServiceWorkers.</p>
|
||
<p>We have already seen some attributes of Response when we looked at <code>fetch()</code>.
|
||
The most obvious candidates are <code>status</code>, an integer (default
|
||
value 200) and <code>statusText</code> (default value “OK”), which correspond
|
||
to the HTTP status code and reason. The <code>ok</code> attribute is just
|
||
a shorthand for checking that <code>status</code> is in the range 200-299
|
||
inclusive.</p>
|
||
<p><code>headers</code> is the Response’s Headers object, with guard “response”.
|
||
The <code>url</code> attribute reflects the URL of the corresponding request.</p>
|
||
<p>Response also has a <code>type</code>, which is “basic”, “cors”, “default”,
|
||
“error” or
|
||
<br>“opaque”.</p>
|
||
<ul>
|
||
<li><code>"basic"</code>: normal, same origin response, with all headers exposed
|
||
except
|
||
<br>“Set-Cookie” and “Set-Cookie2″.</li>
|
||
<li><code>"cors"</code>: response was received from a valid cross-origin request.
|
||
<a
|
||
href="https://fetch.spec.whatwg.org/#concept-filtered-response-cors">Certain headers and the body</a>may be accessed.</li>
|
||
<li><code>"error"</code>: network error. No useful information describing
|
||
the error is available. The Response’s status is 0, headers are empty and
|
||
immutable. This is the type for a Response obtained from <code>Response.error()</code>.</li>
|
||
<li><code>"opaque"</code>: response for “no-cors” request to cross-origin
|
||
resource. <a href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque">Severely<br>
|
||
restricted</a>
|
||
</li>
|
||
</ul>
|
||
<p>The “error” type results in the <code>fetch()</code> Promise rejecting with
|
||
TypeError.</p>
|
||
<p>There are certain attributes that are useful only in a ServiceWorker scope.
|
||
The
|
||
<br>idiomatic way to return a Response to an intercepted request in ServiceWorkers
|
||
is:</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">addEventListener<span style="color: #009900;">(</span><span style="color: #3366CC;">'fetch'</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>event<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
event.<span style="color: #660066;">respondWith</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">new</span> Response<span style="color: #009900;">(</span><span style="color: #3366CC;">"Response body"</span><span style="color: #339933;">,</span> <span style="color: #009900;">{</span>
|
||
headers<span style="color: #339933;">:</span> <span style="color: #009900;">{</span> <span style="color: #3366CC;">"Content-Type"</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">"text/plain"</span> <span style="color: #009900;">}</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>As you can see, Response has a two argument constructor, where both arguments
|
||
are optional. The first argument is a body initializer, and the second
|
||
is a dictionary to set the <code>status</code>, <code>statusText</code> and <code>headers</code>.</p>
|
||
<p>The static method <code>Response.error()</code> simply returns an error
|
||
response. Similarly, <code>Response.redirect(url, status)</code> returns
|
||
a Response resulting in
|
||
<br>a redirect to <code>url</code>.</p>
|
||
|
||
<h2>Dealing with bodies</h2>
|
||
|
||
<p>Both Requests and Responses may contain body data. We’ve been glossing
|
||
over it because of the various data types body may contain, but we will
|
||
cover it in detail now.</p>
|
||
<p>A body is an instance of any of the following types.</p>
|
||
<ul>
|
||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer">ArrayBuffer</a>
|
||
</li>
|
||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView">ArrayBufferView</a> (Uint8Array
|
||
and friends)</li>
|
||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>/
|
||
<a
|
||
href="https://developer.mozilla.org/en-US/docs/Web/API/File">File</a>
|
||
</li>
|
||
<li>string</li>
|
||
<li><a href="https://url.spec.whatwg.org/#interface-urlsearchparams">URLSearchParams</a>
|
||
</li>
|
||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData">FormData</a> –
|
||
currently not supported by either Gecko or Blink. Firefox expects to ship
|
||
this in version 39 along with the rest of Fetch.</li>
|
||
</ul>
|
||
<p>In addition, Request and Response both offer the following methods to
|
||
extract their body. These all return a Promise that is eventually resolved
|
||
with the actual content.</p>
|
||
<ul>
|
||
<li><code>arrayBuffer()</code>
|
||
</li>
|
||
<li><code>blob()</code>
|
||
</li>
|
||
<li><code>json()</code>
|
||
</li>
|
||
<li><code>text()</code>
|
||
</li>
|
||
<li><code>formData()</code>
|
||
</li>
|
||
</ul>
|
||
<p>This is a significant improvement over XHR in terms of ease of use of
|
||
non-text data!</p>
|
||
<p>Request bodies can be set by passing <code>body</code> parameters:</p>
|
||
<div
|
||
class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> form <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> FormData<span style="color: #009900;">(</span>document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">(</span><span style="color: #3366CC;">'login-form'</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
fetch<span style="color: #009900;">(</span><span style="color: #3366CC;">"/login"</span><span style="color: #339933;">,</span> <span style="color: #009900;">{</span>
|
||
method<span style="color: #339933;">:</span> <span style="color: #3366CC;">"POST"</span><span style="color: #339933;">,</span>
|
||
body<span style="color: #339933;">:</span> form
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>Responses take the first argument as the body.</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> res <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Response<span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">new</span> File<span style="color: #009900;">(</span><span style="color: #009900;">[</span><span style="color: #3366CC;">"chunk"</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"chunk"</span><span style="color: #009900;">]</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">"archive.zip"</span><span style="color: #339933;">,</span>
|
||
<span style="color: #009900;">{</span> type<span style="color: #339933;">:</span> <span style="color: #3366CC;">"application/zip"</span> <span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>Both Request and Response (and by extension the <code>fetch()</code> function),
|
||
will try to intelligently <a href="https://fetch.spec.whatwg.org/#concept-bodyinit-extract">determine the content type</a>.
|
||
Request will also automatically set a “Content-Type” header if none is
|
||
set in the dictionary.</p>
|
||
|
||
<h3>Streams and cloning</h3>
|
||
|
||
<p>It is important to realise that Request and Response bodies can only be
|
||
read once! Both interfaces have a boolean attribute <code>bodyUsed</code> to
|
||
determine if it is safe to read or not.</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">var</span> res <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Response<span style="color: #009900;">(</span><span style="color: #3366CC;">"one time use"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>res.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// false</span>
|
||
res.<span style="color: #660066;">text</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>v<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>res.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// true</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>res.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// true</span>
|
||
|
||
res.<span style="color: #660066;">text</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span>.<span style="color: #000066; font-weight: bold;">catch</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>e<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span><span style="color: #3366CC;">"Tried to read already consumed Response"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p>This decision allows easing the transition to an eventual <a href="https://streams.spec.whatwg.org/">stream-based</a> Fetch
|
||
API. The intention is to let applications consume data as it arrives, allowing
|
||
for JavaScript to deal with larger files like videos, and perform things
|
||
like compression and editing on the fly.</p>
|
||
<p>Often, you’ll want access to the body multiple times. For example, you
|
||
can use the upcoming <a href="http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cache-objects">Cache API</a> to
|
||
store Requests and Responses for offline use, and Cache requires bodies
|
||
to be available for reading.</p>
|
||
<p>So how do you read out the body multiple times within such constraints?
|
||
The API provides a <code>clone()</code> method on the two interfaces. This
|
||
will return a clone of the object, with a ‘new’ body. <code>clone()</code> MUST
|
||
be called before the body of the corresponding object has been used. That
|
||
is, <code>clone()</code> first, read later.</p>
|
||
<div class="wp_syntax">
|
||
<table>
|
||
<tbody>
|
||
<tr>
|
||
<td class="code"><pre class="javascript" style="font-family:monospace;">addEventListener<span style="color: #009900;">(</span><span style="color: #3366CC;">'fetch'</span><span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>evt<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #000066; font-weight: bold;">var</span> sheep <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">new</span> Response<span style="color: #009900;">(</span><span style="color: #3366CC;">"Dolly"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>sheep.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// false</span>
|
||
<span style="color: #000066; font-weight: bold;">var</span> clone <span style="color: #339933;">=</span> sheep.<span style="color: #660066;">clone</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>clone.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// false</span>
|
||
|
||
clone.<span style="color: #660066;">text</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>sheep.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// false</span>
|
||
console.<span style="color: #660066;">log</span><span style="color: #009900;">(</span>clone.<span style="color: #660066;">bodyUsed</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// true</span>
|
||
|
||
evt.<span style="color: #660066;">respondWith</span><span style="color: #009900;">(</span>cache.<span style="color: #660066;">add</span><span style="color: #009900;">(</span>sheep.<span style="color: #660066;">clone</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>.<span style="color: #660066;">then</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">function</span><span style="color: #009900;">(</span>e<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
|
||
<span style="color: #000066; font-weight: bold;">return</span> sheep<span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
|
||
<span style="color: #009900;">}</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h2>Future improvements</h2>
|
||
|
||
<p>Along with the transition to streams, Fetch will eventually have the ability
|
||
to abort running <code>fetch()</code>es and some way to report the progress
|
||
of a fetch. These are provided by XHR, but are a little tricky to fit in
|
||
the Promise-based nature of the Fetch API.</p>
|
||
<p>You can contribute to the evolution of this API by participating in discussions
|
||
on the <a href="https://whatwg.org/mailing-list">WHATWG mailing list</a> and
|
||
in the issues in the <a href="https://www.w3.org/Bugs/Public/buglist.cgi?product=WHATWG&component=Fetch&resolution=---">Fetch</a> and
|
||
<a
|
||
href="https://github.com/slightlyoff/ServiceWorker/issues">ServiceWorker</a>specifications.</p>
|
||
<p>For a better web!</p>
|
||
<p><em>The author would like to thank Andrea Marchesini, Anne van Kesteren and Ben<br>
|
||
Kelly for helping with the specification and implementation.</em>
|
||
</p>
|
||
<footer class="entry-meta">
|
||
<p>Posted by <a href="https://hacks.mozilla.org/author/nmarathemozilla-com/"
|
||
title="Posts by Nikhil Marathe" class="url fn" rel="author">Nikhil Marathe</a>
|
||
on
|
||
<time
|
||
datetime="2015-03-10T08:05:41-07:00">March 10, 2015</time>at
|
||
<time datetime="PDT08:05:41-07:00">08:05</time>
|
||
</p>
|
||
<div class="share">
|
||
<div class="socialshare" data-type="small-bubbles"></div>
|
||
</div>
|
||
</footer>
|
||
</article>
|
||
<section id="comments">
|
||
<div id="comment-stream">
|
||
<header class="comments-head">
|
||
<h3>2 comments</h3>
|
||
|
||
<p class="open"><a href="#respond">Post a comment</a>
|
||
</p>
|
||
</header>
|
||
<ol id="comment-list" class="hfeed av">
|
||
<li id="comment-17303" class="comment even thread-even depth-1 hentry">
|
||
<p class="entry-title vcard"> <span class="photo"><img alt="" src="https://secure.gravatar.com/avatar/cc6f7a60f71adaa81b7bc798ebc71be1?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D48&r=G" class="avatar avatar-48 photo" height="48" width="48"></span>
|
||
<cite
|
||
class="author fn">Alexander Petrov</cite> <span class="comment-meta">wrote on <a href="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/comment-page-1/#comment-17303" rel="bookmark" title="Permanent link to this comment by Alexander Petrov"><abbr class="published" title="2015-03-11">March 11th, 2015</abbr> at 02:57</a>:</span>
|
||
|
||
</p>
|
||
<blockquote class="entry-content">
|
||
<p>how do you abort a fetch?</p>
|
||
</blockquote>
|
||
<p class="comment-util"><a class="comment-reply-link" href="/2015/03/this-api-is-so-fetching/?replytocom=17303#respond"
|
||
onclick="return addComment.moveForm( "comment-17303", "17303", "respond", "28260" )"
|
||
aria-label="Reply to Alexander Petrov">Reply</a>
|
||
</p>
|
||
<ol class="children">
|
||
<li id="comment-17305" class="comment byuser comment-author-nmarathemozilla-com bypostauthor odd alt depth-2 hentry">
|
||
<p class="entry-title vcard"> <a href="http://blog.nikhilism.com" class="url" rel="nofollow external"
|
||
title="http://blog.nikhilism.com">
|
||
<span class="photo"><img alt="" src="https://secure.gravatar.com/avatar/098bc26c1d2d2b425b258cff67044ac1?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D48&r=G" class="avatar avatar-48 photo" height="48" width="48"></span> <cite class="author fn">Nikhil Marathe</cite>
|
||
</a>
|
||
<span class="comment-meta">wrote on <a href="https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/comment-page-1/#comment-17305" rel="bookmark" title="Permanent link to this comment by Nikhil Marathe"><abbr class="published" title="2015-03-11">March 11th, 2015</abbr> at 08:00</a>:</span>
|
||
|
||
</p>
|
||
<blockquote class="entry-content">
|
||
<p>At this point there is no way to do so. As mentioned in the future improvements
|
||
sections, there are ongoing attempts to find a nice way to plug abort()
|
||
into Promise based APIs.</p>
|
||
</blockquote>
|
||
<p class="comment-util"><a class="comment-reply-link" href="/2015/03/this-api-is-so-fetching/?replytocom=17305#respond"
|
||
onclick="return addComment.moveForm( "comment-17305", "17305", "respond", "28260" )"
|
||
aria-label="Reply to Nikhil Marathe">Reply</a>
|
||
</p>
|
||
</li>
|
||
<!-- #comment-## -->
|
||
</ol>
|
||
<!-- .children -->
|
||
</li>
|
||
<!-- #comment-## -->
|
||
</ol>
|
||
</div>
|
||
<div id="respond">
|
||
<form id="comment-form" action="https://hacks.mozilla.org/wp-comments-post.php"
|
||
method="post">
|
||
<fieldset>
|
||
<legend><span>Post Your Comment</span>
|
||
</legend>
|
||
<p id="cancel-comment-reply"><a rel="nofollow" id="cancel-comment-reply-link" href="/2015/03/this-api-is-so-fetching/#respond"
|
||
style="display:none;">Cancel Reply</a>
|
||
</p>
|
||
<ol>
|
||
<li id="cmt-name">
|
||
<label for="author">Your name <abbr title="(required)">*</abbr>
|
||
</label>
|
||
<input type="text" name="author" id="author" size="25" required="" aria-required="true">
|
||
</li>
|
||
<li id="cmt-email">
|
||
<label for="email">Your e-mail <abbr title="(required)">*</abbr>
|
||
</label>
|
||
<input type="email" name="email" id="email" size="25" required="" aria-required="true">
|
||
</li>
|
||
<li id="cmt-web">
|
||
<label for="url">Your website</label>
|
||
<input type="url" name="url" id="url" size="25">
|
||
</li>
|
||
<li id="cmt-ackbar">
|
||
<label for="age">Spam robots, please fill in this field. Humans should leave it blank.</label>
|
||
<input
|
||
type="text" name="age" id="age" size="4" tabindex="-1">
|
||
</li>
|
||
<li id="cmt-cmt">
|
||
<label for="comment">Your comment</label>
|
||
<textarea name="comment" id="comment" cols="50" rows="10"
|
||
required="required" aria-required="true"></textarea>
|
||
</li>
|
||
<li id="comment-submit">
|
||
<button name="submit" type="submit">Submit Comment</button>
|
||
<input type="hidden" name="comment_post_ID" value="28260"
|
||
id="comment_post_ID">
|
||
<input type="hidden" name="comment_parent" id="comment_parent" value="0">
|
||
<p style="display: none;">
|
||
<input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce"
|
||
value="b601694886">
|
||
</p>
|
||
<!-- BEGIN: subscribe to comments reloaded -->
|
||
<p class="comment-form-subscriptions">
|
||
<label for="subscribe-reloaded">
|
||
<input style="width:30px" type="checkbox" name="subscribe-reloaded" id="subscribe-reloaded"
|
||
value="yes">Notify me of followup comments via e-mail. You can also <a href="https://hacks.mozilla.org/comment-subscriptions/?srp=28260&sra=s">subscribe</a> without
|
||
commenting.</label>
|
||
</p>
|
||
<!-- END: subscribe to comments reloaded -->
|
||
<p style="display: none;">
|
||
<input type="hidden" id="ak_js" name="ak_js" value="212">
|
||
</p>
|
||
</li>
|
||
</ol>
|
||
</fieldset>
|
||
</form>
|
||
</div>
|
||
</section>
|
||
<script>
|
||
jQuery("#comment-form").submit(function() { return fc_checkform('req'); });
|
||
</script>
|
||
</main>
|
||
<!-- /#content-main -->
|
||
<div id="content-sub">
|
||
<ul id="widgets">
|
||
<li class="widget author">
|
||
<h3>About the Author</h3>
|
||
|
||
<div class="vcard">
|
||
<h4 class="fn">
|
||
<a class="url" href="http://blog.nikhilism.com" rel="external me">Nikhil Marathe <span class="photo"><img alt="" src="https://secure.gravatar.com/avatar/098bc26c1d2d2b425b258cff67044ac1?s=48&d=https%3A%2F%2Fsecure.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D48&r=G" class="avatar avatar-48 photo" height="48" width="48"></span> </a></h4>
|
||
|
||
<p>Nikhil works on implementing Web APIs in Gecko. He is currently hacking
|
||
on ServiceWorkers, Fetch and parts of the Notification and Push APIs.</p>
|
||
<ul
|
||
class="author-meta">
|
||
<li><a href="http://blog.nikhilism.com" class="website" rel="me">blog.nikhilism.com</a>
|
||
</li>
|
||
</ul>
|
||
<p><a class="url" href="https://hacks.mozilla.org/author/nmarathemozilla-com/">Read more articles by Nikhil Marathe…</a>
|
||
</p>
|
||
</div>
|
||
</li>
|
||
<li class="widget categories">
|
||
<h3>Articles by Category</h3>
|
||
|
||
<ul class="cat-list" role="navigation">
|
||
<li class="cat-item cat-item-74992"><a href="https://hacks.mozilla.org/category/35-days/">35 Days</a> (45)</li>
|
||
<li
|
||
class="cat-item cat-item-75188"><a href="https://hacks.mozilla.org/category/font-face/">@font-face</a> (9)</li>
|
||
<li
|
||
class="cat-item cat-item-75450"><a href="https://hacks.mozilla.org/category/a-node-js-holiday-season/">A Node.JS Holiday Season</a> (12)</li>
|
||
<li
|
||
class="cat-item cat-item-75682"><a href="https://hacks.mozilla.org/category/abouthacks/">about:hacks</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-50"><a href="https://hacks.mozilla.org/category/accessibility/">Accessibility</a> (1)</li>
|
||
<li
|
||
class="cat-item cat-item-119"><a href="https://hacks.mozilla.org/category/add-ons/">Add-ons</a> (16)</li>
|
||
<li
|
||
class="cat-item cat-item-86093"><a href="https://hacks.mozilla.org/category/javascript/animations/">Animations</a> (7)</li>
|
||
<li
|
||
class="cat-item cat-item-4213"><a href="https://hacks.mozilla.org/category/apps/">Apps</a> (94)</li>
|
||
<li
|
||
class="cat-item cat-item-76011"><a href="https://hacks.mozilla.org/category/ask-mdn/">Ask MDN</a> (3)</li>
|
||
<li
|
||
class="cat-item cat-item-25981"><a href="https://hacks.mozilla.org/category/asm-js/">asm.js</a> (10)</li>
|
||
<li
|
||
class="cat-item cat-item-221"><a href="https://hacks.mozilla.org/category/audio/">Audio</a> (42)</li>
|
||
<li
|
||
class="cat-item cat-item-76289"><a href="https://hacks.mozilla.org/category/bleeding-edge/">Bleeding edge</a> (12)</li>
|
||
<li
|
||
class="cat-item cat-item-76432"><a href="https://hacks.mozilla.org/category/boottogecko/">Boot to Gecko (B2G)</a> (12)</li>
|
||
<li
|
||
class="cat-item cat-item-76712"><a href="https://hacks.mozilla.org/category/brick/">Brick</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-76814"><a href="https://hacks.mozilla.org/category/browserid-2/">BrowserID</a> (4)</li>
|
||
<li
|
||
class="cat-item cat-item-134"><a href="https://hacks.mozilla.org/category/canvas/">Canvas</a> (44)</li>
|
||
<li
|
||
class="cat-item cat-item-23095"><a href="https://hacks.mozilla.org/category/challenge/">Challenge</a> (9)</li>
|
||
<li
|
||
class="cat-item cat-item-70"><a href="https://hacks.mozilla.org/category/conferences/">Conferences</a> (36)</li>
|
||
<li
|
||
class="cat-item cat-item-176756"><a href="https://hacks.mozilla.org/category/cordova/">Cordova</a> (1)</li>
|
||
<li
|
||
class="cat-item cat-item-133"><a href="https://hacks.mozilla.org/category/css/">CSS</a> (109)</li>
|
||
<li
|
||
class="cat-item cat-item-185"><a href="https://hacks.mozilla.org/category/debugging/">Debugging</a> (11)</li>
|
||
<li
|
||
class="cat-item cat-item-19490"><a href="https://hacks.mozilla.org/category/demo/">Demo</a> (93)</li>
|
||
<li
|
||
class="cat-item cat-item-86249"><a href="https://hacks.mozilla.org/category/mdn/demo-studio/">Demo Studio</a> (11)</li>
|
||
<li
|
||
class="cat-item cat-item-76969"><a href="https://hacks.mozilla.org/category/dev-derby/">Dev Derby</a> (56)</li>
|
||
<li
|
||
class="cat-item cat-item-297"><a href="https://hacks.mozilla.org/category/developer-tools/">Developer Tools</a> (73)</li>
|
||
<li
|
||
class="cat-item cat-item-77083"><a href="https://hacks.mozilla.org/category/device-apis/">Device APIs</a> (14)</li>
|
||
<li
|
||
class="cat-item cat-item-894"><a href="https://hacks.mozilla.org/category/docs/">Docs</a> (96)</li>
|
||
<li
|
||
class="cat-item cat-item-230"><a href="https://hacks.mozilla.org/category/dom/">DOM</a> (23)</li>
|
||
<li
|
||
class="cat-item cat-item-77434"><a href="https://hacks.mozilla.org/category/drag-and-drop/">Drag and Drop</a> (10)</li>
|
||
<li
|
||
class="cat-item cat-item-817"><a href="https://hacks.mozilla.org/category/drumbeat/">Drumbeat</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-77621"><a href="https://hacks.mozilla.org/category/evangelism-reps/">Evangelism Reps</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-57"><a href="https://hacks.mozilla.org/category/event/">Event</a> (26)</li>
|
||
<li
|
||
class="cat-item cat-item-25569"><a href="https://hacks.mozilla.org/category/feature/">Feature</a> (46)</li>
|
||
<li
|
||
class="cat-item cat-item-7110"><a href="https://hacks.mozilla.org/category/featured/">Featured Article</a> (185)</li>
|
||
<li
|
||
class="cat-item cat-item-77870"><a href="https://hacks.mozilla.org/category/demo/featured-demo/">Featured Demo</a> (27)</li>
|
||
<li
|
||
class="cat-item cat-item-78138"><a href="https://hacks.mozilla.org/category/feedback-channels/">Feedback channels</a> (4)</li>
|
||
<li
|
||
class="cat-item cat-item-78354"><a href="https://hacks.mozilla.org/category/fileapi/">FileAPI</a> (17)</li>
|
||
<li
|
||
class="cat-item cat-item-500"><a href="https://hacks.mozilla.org/category/firebug/">Firebug</a> (16)</li>
|
||
<li
|
||
class="cat-item cat-item-30"><a href="https://hacks.mozilla.org/category/firefox/">Firefox</a> (223)</li>
|
||
<li
|
||
class="cat-item cat-item-36038"><a href="https://hacks.mozilla.org/category/firefox/firefox-aurora/">Firefox Aurora</a> (30)</li>
|
||
<li
|
||
class="cat-item cat-item-8802"><a href="https://hacks.mozilla.org/category/firefox/firefox-beta/">Firefox Beta</a> (3)</li>
|
||
<li
|
||
class="cat-item cat-item-78585"><a href="https://hacks.mozilla.org/category/firefox/firefox-development-highlights/">Firefox Development Highlights</a> (12)</li>
|
||
<li
|
||
class="cat-item cat-item-78857"><a href="https://hacks.mozilla.org/category/firefox/firefox-nightly/">Firefox Nightly</a> (10)</li>
|
||
<li
|
||
class="cat-item cat-item-24660"><a href="https://hacks.mozilla.org/category/firefox-os/">Firefox OS</a> (114)</li>
|
||
<li
|
||
class="cat-item cat-item-27876"><a href="https://hacks.mozilla.org/category/games-2/">Games</a> (40)</li>
|
||
<li
|
||
class="cat-item cat-item-79240"><a href="https://hacks.mozilla.org/category/geolocation/">Geolocation</a> (10)</li>
|
||
<li
|
||
class="cat-item cat-item-79514"><a href="https://hacks.mozilla.org/category/hackability/">hackability</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-79853"><a href="https://hacks.mozilla.org/category/hackdays/">hackdays</a> (7)</li>
|
||
<li
|
||
class="cat-item cat-item-80032"><a href="https://hacks.mozilla.org/category/history-api/">History API</a> (1)</li>
|
||
<li
|
||
class="cat-item cat-item-254"><a href="https://hacks.mozilla.org/category/html5/">HTML5</a> (176)</li>
|
||
<li
|
||
class="cat-item cat-item-8633"><a href="https://hacks.mozilla.org/category/identity/">Identity</a> (8)</li>
|
||
<li
|
||
class="cat-item cat-item-16182"><a href="https://hacks.mozilla.org/category/images/">Images</a> (8)</li>
|
||
<li
|
||
class="cat-item cat-item-100532"><a href="https://hacks.mozilla.org/category/indexeddb/">IndexedDB</a> (16)</li>
|
||
<li
|
||
class="cat-item cat-item-453"><a href="https://hacks.mozilla.org/category/interviews/">Interviews</a> (4)</li>
|
||
<li
|
||
class="cat-item cat-item-4543"><a href="https://hacks.mozilla.org/category/jagermonkey/">JägerMonkey</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-128"><a href="https://hacks.mozilla.org/category/javascript/">JavaScript</a> (141)</li>
|
||
<li
|
||
class="cat-item cat-item-697"><a href="https://hacks.mozilla.org/category/labs/">Labs</a> (3)</li>
|
||
<li
|
||
class="cat-item cat-item-4883"><a href="https://hacks.mozilla.org/category/mdn/learning/">Learning</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-199"><a href="https://hacks.mozilla.org/category/localization/">Localization</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-80317"><a href="https://hacks.mozilla.org/category/localstorage/">localStorage</a> (4)</li>
|
||
<li
|
||
class="cat-item cat-item-766"><a href="https://hacks.mozilla.org/category/mdn/">MDN</a> (82)</li>
|
||
<li
|
||
class="cat-item cat-item-80686"><a href="https://hacks.mozilla.org/category/css/media-queries/">Media Queries</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-81062"><a href="https://hacks.mozilla.org/category/missionmozilla/">Mission:Mozilla</a> (9)</li>
|
||
<li
|
||
class="cat-item cat-item-124"><a href="https://hacks.mozilla.org/category/mobile/">Mobile</a> (44)</li>
|
||
<li
|
||
class="cat-item cat-item-5"><a href="https://hacks.mozilla.org/category/mozilla/">Mozilla</a> (32)</li>
|
||
<li
|
||
class="cat-item cat-item-81241"><a href="https://hacks.mozilla.org/category/mozilla-hacks-weekly/">Mozilla Hacks Weekly</a> (64)</li>
|
||
<li
|
||
class="cat-item cat-item-81399"><a href="https://hacks.mozilla.org/category/multi-touch/">Multi-touch</a> (7)</li>
|
||
<li
|
||
class="cat-item cat-item-58"><a href="https://hacks.mozilla.org/category/news/">News</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-81514"><a href="https://hacks.mozilla.org/category/node-js/">Node.js</a> (21)</li>
|
||
<li
|
||
class="cat-item cat-item-20266"><a href="https://hacks.mozilla.org/category/offline/">Offline</a> (11)</li>
|
||
<li
|
||
class="cat-item cat-item-264728"><a href="https://hacks.mozilla.org/category/p2p-web/">P2P Web</a> (3)</li>
|
||
<li
|
||
class="cat-item cat-item-27786"><a href="https://hacks.mozilla.org/category/payments/">Payments</a> (7)</li>
|
||
<li
|
||
class="cat-item cat-item-81886"><a href="https://hacks.mozilla.org/category/people-of-games/">People of Games</a> (1)</li>
|
||
<li
|
||
class="cat-item cat-item-82131"><a href="https://hacks.mozilla.org/category/people-of-html5/">People of HTML5</a> (11)</li>
|
||
<li
|
||
class="cat-item cat-item-311"><a href="https://hacks.mozilla.org/category/performance/">Performance</a> (35)</li>
|
||
<li
|
||
class="cat-item cat-item-82359"><a href="https://hacks.mozilla.org/category/persona-2/">Persona</a> (3)</li>
|
||
<li
|
||
class="cat-item cat-item-82536"><a href="https://hacks.mozilla.org/category/presentation-2/">Presentation</a> (14)</li>
|
||
<li
|
||
class="cat-item cat-item-847"><a href="https://hacks.mozilla.org/category/privacy/">privacy</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-60"><a href="https://hacks.mozilla.org/category/qa/">QA</a> (2)</li>
|
||
<li class="cat-item cat-item-538"><a href="https://hacks.mozilla.org/category/release/">Release</a> (4)</li>
|
||
<li
|
||
class="cat-item cat-item-907"><a href="https://hacks.mozilla.org/category/research/">Research</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-3389"><a href="https://hacks.mozilla.org/category/screencast/">Screencast</a> (6)</li>
|
||
<li
|
||
class="cat-item cat-item-69"><a href="https://hacks.mozilla.org/category/security/">Security</a> (14)</li>
|
||
<li
|
||
class="cat-item cat-item-82787"><a href="https://hacks.mozilla.org/category/serviceworkers/">ServiceWorkers</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-83024"><a href="https://hacks.mozilla.org/category/spdy/">SPDY</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-83193"><a href="https://hacks.mozilla.org/category/sprints/">Sprints</a> (17)</li>
|
||
<li
|
||
class="cat-item cat-item-248"><a href="https://hacks.mozilla.org/category/standards/">Standards</a> (53)</li>
|
||
<li
|
||
class="cat-item cat-item-315"><a href="https://hacks.mozilla.org/category/survey/">Survey</a> (8)</li>
|
||
<li
|
||
class="cat-item cat-item-131"><a href="https://hacks.mozilla.org/category/svg/">SVG</a> (16)</li>
|
||
<li
|
||
class="cat-item cat-item-725"><a href="https://hacks.mozilla.org/category/test-day/">Test Day</a> (1)</li>
|
||
<li
|
||
class="cat-item cat-item-265"><a href="https://hacks.mozilla.org/category/testing/">Testing</a> (3)</li>
|
||
<li
|
||
class="cat-item cat-item-610"><a href="https://hacks.mozilla.org/category/tools/">Tools</a> (9)</li>
|
||
<li
|
||
class="cat-item cat-item-467"><a href="https://hacks.mozilla.org/category/tracemonkey/">TraceMonkey</a> (9)</li>
|
||
<li
|
||
class="cat-item cat-item-1"><a href="https://hacks.mozilla.org/category/uncategorized/">Uncategorized</a> (1)</li>
|
||
<li
|
||
class="cat-item cat-item-220"><a href="https://hacks.mozilla.org/category/video/">Video</a> (63)</li>
|
||
<li
|
||
class="cat-item cat-item-83360"><a href="https://hacks.mozilla.org/category/videoseries/">Videoseries</a> (11)</li>
|
||
<li
|
||
class="cat-item cat-item-83698"><a href="https://hacks.mozilla.org/category/web-components/">Web Components</a> (6)</li>
|
||
<li
|
||
class="cat-item cat-item-83947"><a href="https://hacks.mozilla.org/category/web-developer-toolbox/">Web Developer Toolbox</a> (5)</li>
|
||
<li
|
||
class="cat-item cat-item-84203"><a href="https://hacks.mozilla.org/category/web-developers/">Web Developers</a> (55)</li>
|
||
<li
|
||
class="cat-item cat-item-16188"><a href="https://hacks.mozilla.org/category/web-workers/">Web Workers</a> (4)</li>
|
||
<li
|
||
class="cat-item cat-item-84514"><a href="https://hacks.mozilla.org/category/webapi/">WebAPI</a> (25)</li>
|
||
<li
|
||
class="cat-item cat-item-19673"><a href="https://hacks.mozilla.org/category/webfwd/">WebFWD</a> (7)</li>
|
||
<li
|
||
class="cat-item cat-item-6946"><a href="https://hacks.mozilla.org/category/webgl/">WebGL</a> (39)</li>
|
||
<li
|
||
class="cat-item cat-item-84672"><a href="https://hacks.mozilla.org/category/webinars/">Webinars</a> (6)</li>
|
||
<li
|
||
class="cat-item cat-item-15881"><a href="https://hacks.mozilla.org/category/webrtc/">WebRTC</a> (33)</li>
|
||
<li
|
||
class="cat-item cat-item-84974"><a href="https://hacks.mozilla.org/category/websocket/">WebSocket</a> (9)</li>
|
||
<li
|
||
class="cat-item cat-item-85295"><a href="https://hacks.mozilla.org/category/wiki-wednesday/">Wiki Wednesday</a> (43)</li>
|
||
<li
|
||
class="cat-item cat-item-85568"><a href="https://hacks.mozilla.org/category/x-tag/">X-Tag</a> (2)</li>
|
||
<li
|
||
class="cat-item cat-item-85881"><a href="https://hacks.mozilla.org/category/xmlhttprequest/">XMLHttpRequest</a> (13)</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<!-- /#content-sub -->
|
||
</div>
|
||
<!-- /#content -->
|
||
<footer id="site-info">
|
||
<nav id="nav-legal">
|
||
<ul>
|
||
<li><a href="https://www.mozilla.org/privacy/websites/" rel="external">Privacy Policy</a>
|
||
</li>
|
||
<li><a href="https://www.mozilla.org/about/legal.html" rel="external">Legal Notices</a>
|
||
</li>
|
||
<li><a href="https://www.mozilla.org/legal/fraud-report/" rel="external">Report Trademark Abuse</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
<p id="copyright">Except where otherwise noted, content on this site is licensed under the
|
||
<br><a href="https://creativecommons.org/licenses/by-sa/3.0/" rel="license external">Creative Commons Attribution Share-Alike License v3.0</a> or
|
||
any later version.</p>
|
||
<nav id="nav-footer">
|
||
<h5>hacks.mozilla.org:</h5>
|
||
|
||
<ul role="navigation">
|
||
<li><a href="https://hacks.mozilla.org">Home</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/articles/">Articles</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/demos/">Demos</a>
|
||
</li>
|
||
<li><a href="https://hacks.mozilla.org/about/">About</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</footer>
|
||
<script src="https://www.mozilla.org/tabzilla/media/js/tabzilla.js"></script>
|
||
<script>
|
||
// <![CDATA[
|
||
jQuery(document).ready(function(){
|
||
jQuery(document.body).addClass("js");
|
||
});
|
||
// ]]>
|
||
</script>
|
||
<script type="text/javascript" src="https://blog.mozilla.org/hacks/wp-content/plugins/akismet/_inc/form.js?ver=3.0.4"></script>
|
||
<script type="text/javascript" src="https://hacks.mozilla.org/wp-includes/js/comment-reply.min.js?ver=4.1"></script>
|
||
</div>
|
||
</body>
|
||
|
||
</html>
|
||
<!-- Dynamic page generated in 0.592 seconds. -->
|
||
<!-- Cached page generated by WP-Super-Cache on 2015-03-13 03:27:44 -->
|
||
<!-- super cache --> |