Upgrade to Pro — share decks privately, control downloads, hide ads and more …

fetch is the new XHR

Avatar for othree othree
August 16, 2015

fetch is the new XHR

Avatar for othree

othree

August 16, 2015
Tweet

More Decks by othree

Other Decks in Technology

Transcript

  1. Ajax • Most popular pattern based on XHR • Jesse

    James Garrett named it “AJAX” • Foundation of Single Page Application http://www.adaptivepath.com/ideas/ajax-new-approach-web-applications/
  2. XHR Spec • W3C Working Draft since 2006, Level 2

    since 2008 • WHATWG Living Standard since 2011
  3. function uploadFiles(url, files) { var formData = new FormData(); for

    (var i = 0, file; file = files[i]; ++i) { formData.append(file.name, file); } var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onload = function(e) { ... }; xhr.send(formData); // multipart/form-data } document.querySelector('input[type="file"]') .addEventListener('change', function(e) { uploadFiles('/server', this.files); }, false);
  4. function uploadFiles(url, files) { var formData = new FormData(); for

    (var i = 0, file; file = files[i]; ++i) { formData.append(file.name, file); } var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onload = function(e) { ... }; xhr.send(formData); // multipart/form-data } document.querySelector(‘input[type="file"]') .addEventListener('change', function(e) { uploadFiles('/server', this.files); }, false);
  5. function uploadFiles(url, files) { var formData = new FormData(); for

    (var i = 0, file; file = files[i]; ++i) { formData.append(file.name, file); } var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onload = function(e) { ... }; xhr.send(formData); // multipart/form-data } document.querySelector(‘input[type="file"]') .addEventListener('change', function(e) { uploadFiles('/server', this.files); }, false);
  6. function uploadFiles(url, files) { var formData = new FormData(); for

    (var i = 0, file; file = files[i]; ++i) { formData.append(file.name, file); } var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onload = function(e) { ... }; xhr.send(formData); // multipart/form-data } document.querySelector(‘input[type="file"]') .addEventListener('change', function(e) { uploadFiles('/server', this.files); }, false);
  7. function uploadFiles(url, files) { var formData = new FormData(); for

    (var i = 0, file; file = files[i]; ++i) { formData.append(file.name, file); } var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onload = function(e) { ... }; xhr.send(formData); // multipart/form-data } document.querySelector(‘input[type="file"]') .addEventListener('change', function(e) { uploadFiles('/server', this.files); }, false);
  8. Fetch • The unified architecture of resource fetching • img,

    script, css, cursor image, …etc • fetch() JavaScript API
  9. Fetch • The unified architecture of resource fetching • img,

    script, css, cursor image, …etc • fetch() JavaScript API Today’s
  10. fetch • Promise based • JSON support • Simple naming,

    options object • Designed as low level API
  11. fetch('./api/entry', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body:

    JSON.stringify(data) }).then(function(response) { response.json().then(data => console.log(data)); return response; });
  12. var obj = { key1: 'value1', key2: [10, 20, 30]

    }; var str = $.param(obj); // "key1=value1&key2%5B%5D=10&key2%5B%5D=20&key2%5B%5D=30" https://www.npmjs.com/package/jquery-param
  13. var obj = { key1: 'value1', key2: [10, 20, 30]

    }; var str = $.param(obj); // "key1=value1&key2%5B%5D=10&key2%5B%5D=20&key2%5B%5D=30" http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
  14. var obj = { key1: 'value1', key2: [10, 20, 30]

    }; var str = $.param(obj); // "key1=value1&key2%5B%5D=10&key2%5B%5D=20&key2%5B%5D=30" // key1=value1 & // key2[]=10 & // key2[]=20 & // key2[]=30 http://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
  15. no-cors • Don’t check CORS • Get opaque response •

    For ServiceWorker • XHR can’t do this
  16. RFC 2616 Multiple message-header fields with the same field-name MAY

    be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)] http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
  17. Header Class • New global class • For both request

    and response headers https://developer.mozilla.org/en-US/docs/Web/API/Headers
  18. var h = new Headers(); h.append( 'Set-Cookie', 'JSESSIONID=alphabeta120394049; HttpOnly' );

    h.append( 'Set-Cookie', 'AWSELBID=baaadbeef6767676767690220; Path=/alpha' ); fetch(url, { headers: h });
  19. var h = new Headers(); h.append( 'Set-Cookie', 'JSESSIONID=alphabeta120394049; HttpOnly' );

    h.append( 'Set-Cookie', 'AWSELBID=baaadbeef6767676767690220; Path=/alpha' ); fetch(url, { headers: h });
  20. var h = new Headers(); h.append( 'Set-Cookie', 'JSESSIONID=alphabeta120394049; HttpOnly' );

    h.append( 'Set-Cookie', 'AWSELBID=baaadbeef6767676767690220; Path=/alpha' ); fetch(url, { headers: h });
  21. Means • Fetch promise will resolve even when server respond

    404, 500 … • Request is complete so Promise is resolved.
  22. Response Body • For formatted response body • No auto

    format detection • Body can consume only once
 (save memory) • Use clone when need consume twice
  23. Issue #61 • Fix the different behaviors • Request will

    not able to reuse in the future https://github.com/whatwg/fetch/issues/61
  24. Fact • Debug:
 Chrome, at ‘other tab’, request body not

    shows
 Firefox, depend on response type
  25. Fact • Safety flag for CORS not affect fetch 


    Affect Electron app 
 Use XHR + polyfill instead
  26. Fact • Not able to cancel a fetch • Issue

    #27 • No solution now https://github.com/whatwg/fetch/issues/27
  27. Fact • Not support progress now • fetch-with-streams • Future

    spec https://github.com/yutakahirano/fetch-with-streams
  28. fetch(url).then(response => { var reader = response.body.getReader(); var decoder =

    new TextDecoder(); function drain(valueSoFar) { return reader.read().then(function(result) { valueSoFar += decoder.decode(result.value || new Uint8Arr if (result.done) return valueSoFar; return drain(valueSoFar); }); } return drain(); }).then(function(fullText) { console.log(fullText); }); https://github.com/whatwg/fetch/issues/28#issuecomment-87209944
  29. fetch(url).then(response => { var reader = response.body.getReader(); var decoder =

    new TextDecoder(); function drain(valueSoFar) { return reader.read().then(function(result) { valueSoFar += decoder.decode(result.value || new Uint8Arr if (result.done) return valueSoFar; return drain(valueSoFar); }); } return drain(); }).then(function(fullText) { console.log(fullText); });
  30. fetch(url).then(response => { var reader = response.body.getReader(); var decoder =

    new TextDecoder(); function drain(valueSoFar) { return reader.read().then(function(result) { valueSoFar += decoder.decode(result.value || new Uint8Arr if (result.done) return valueSoFar; return drain(valueSoFar); }); } return drain(); }).then(function(fullText) { console.log(fullText); });
  31. fetch(url).then(response => { var reader = response.body.getReader(); var decoder =

    new TextDecoder(); function drain(valueSoFar) { return reader.read().then(function(result) { valueSoFar += decoder.decode(result.value || new Uint8Arr if (result.done) return valueSoFar; return drain(valueSoFar); }); } return drain(); }).then(function(fullText) { console.log(fullText); });
  32. fetch(url).then(response => { var reader = response.body.getReader(); var decoder =

    new TextDecoder(); function drain(valueSoFar) { return reader.read().then(function(result) { valueSoFar += decoder.decode(result.value || new Uint8Arr if (result.done) return valueSoFar; return drain(valueSoFar); }); } return drain(); }).then(function(fullText) { console.log(fullText); });
  33. fetch(url).then(response => { var reader = response.body.getReader(); var decoder =

    new TextDecoder(); function drain(valueSoFar) { return reader.read().then(function(result) { valueSoFar += decoder.decode(result.value || new Uint8Arr if (result.done) return valueSoFar; return drain(valueSoFar); }); } return drain(); }).then(function(fullText) { console.log(fullText); });
  34. fetch(url).then(async response => { var reader = response.body.getReader(); var decoder

    = new TextDecoder(); var fullText = ''; var result; do { result = await reader.read(); fullText += decoder.decode(result.value || new Uint8Array, } while (!result.done); console.log(fullText); }); https://github.com/whatwg/fetch/issues/28#issuecomment-87209944
  35. fetch(url).then(async response => { var reader = response.body.getReader(); var decoder

    = new TextDecoder(); var fullText = ''; var result; do { result = await reader.read(); fullText += decoder.decode(result.value || new Uint8Array, } while (!result.done); console.log(fullText); });
  36. fetch(url).then(async response => { var reader = response.body.getReader(); var decoder

    = new TextDecoder(); var fullText = ''; var result; do { result = await reader.read(); fullText += decoder.decode(result.value || new Uint8Array, } while (!result.done); console.log(fullText); });
  37. fetch(url).then(async response => { var reader = response.body.getReader(); var decoder

    = new TextDecoder(); var fullText = ''; var result; do { result = await reader.read(); fullText += decoder.decode(result.value || new Uint8Array,{ } while (!result.done); console.log(fullText); });
  38. Current Status • Lots of new stuff is on the

    way • Streams, cancel • Browser integration • Cache, HTTP/2, CSP, subresource integrity,
 GET with body, busy indicator
  39. But • fetch() is low level API • Need write

    extra codes • Hard to deal with general case • So there is fetch-er
  40. fetch-er • My open source project • A fetch helper,

    like jQuery.ajax • Named ‘fetch-er’ • NPM ‘fetcher’ already taken…
  41. Why • fetch is low level API • Already familiar

    with jQuery.ajax API • Don’t repeat yourself
  42. Repeat? • I must generate request body • I must

    detect response type • I must reject promise if response isn't ok
  43. Features • Auto generate request body • Auto parse response

    type and convert data • jQuery similar behavior • Timeout support • Global options
  44. Dealing Response • Always return an array
 (Promise only accepts

    one value) • [data, statusText, response]
  45. Target User • Want to use ES6 Promise to control

    flow • Don’t want to deal with data formatting stuff • Familiar with jQuery.ajax
  46. Q?