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

fetch is the new XHR

othree
August 16, 2015

fetch is the new XHR

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?