本文經過實踐從古至今對XMLHttpRequest
封裝的各類方式,來了解在es中異步編程的實現細節和設計模式。javascript
XMLHttpRequest
原生寫法var xhr = new XMLHttpRequest() xhr.timeout = 2000 xhr.open("POST", "path/to/api") xhr.onload= function () {console.log(xhr.status,xhr.responseText)} xhr.setRequestHeader("Content-type","text/plain;charset=UTF-8") xhr.send('{"key":"value"}')
傳值方式實現java
function request(method, url, done) { var xhr = new XMLHttpRequest() xhr.open(method, url) xhr.onload = function () { if (this.status >= 200 && this.status < 300) done(null, xhr.response) else done(xhr.response) } xhr.onerror = function () {done(xhr.response)} xhr.send() } //--- request('GET', 'path/to/api', function (err, res) { if (err){console.error(err)} console.log(res) })
傳對象方式實現編程
function request(obj){ var xhr = new XMLHttpRequest() xhr.open(obj.method, obj.url) xhr.onload= function () { if (this.status >= 200 && this.status < 300) obj.success(xhr.response) else obj.fail(xhr.response) } xhr.onerror= function () {obj.fail(xhr.response)} for(let key in obj.header){xhr.setRequestHeader(key ,obj.header[key])} xhr.send(obj.data) } //--- request({ url: 'path/to/api', data: {}, method:"GET", header: {'Content-type': 'application/json'}, success(res) {console.log(res)}, fail(err) {console.error(err)} })
使用 Promise - MDN
Promise 本質上是一個綁定了回調的對象,而不是將回調傳進函數內部。
傳值方式實現json
function requestPromise(method, url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.open(method, url) xhr.onload = function () { if (this.status >= 200 && this.status < 300) resolve(xhr.response) else reject({status: this.status,statusText: xhr.statusText}) } xhr.onerror = function () { reject({status: this.status,statusText: xhr.statusText}) } xhr.send() }) } // --- requestPromise('GET', 'path/to/api') .then(function (res1) { return makeRequest('GET', res1.url) }) .then(function (res2) { console.log(res2) }) .catch(function (err) { console.error(err) });
傳對象方式實現設計模式
function makeRequest (opts) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open(opts.method, opts.url); xhr.onload = function () { if (this.status >= 200 && this.status < 300) { resolve(xhr.response); } else { reject({ status: this.status, statusText: xhr.statusText }); } }; xhr.onerror = function () { reject({ status: this.status, statusText: xhr.statusText }); }; if (opts.headers) { Object.keys(opts.headers).forEach(function (key) { xhr.setRequestHeader(key, opts.headers[key]); }); } var params = opts.params; // We'll need to stringify if we've been given an object // If we have a string, this is skipped. if (params && typeof params === 'object') { params = Object.keys(params).map(function (key) { return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]); }).join('&'); } xhr.send(params); }); } // Headers and params are optional makeRequest({ method: 'GET', url: 'http://example.com' }) .then(function (datums) { return makeRequest({ method: 'POST', url: datums.url, params: { score: 9001 }, headers: { 'X-Subliminal-Message': 'Upvote-this-answer' } }); }) .catch(function (err) { console.error('Augh, there was an error!', err.statusText); });
fetch-MDNapi
fetch('path/to/api', {credentials: 'include'}) .then(function(response) { if (response.status >= 400) { throw new Error("Bad response from server"); } return response.json(); }) .then(function(stories) { console.log(stories); });
Request-MDNpromise
var myRequest = new Request( 'path/to/api', { method: 'GET', headers: {'Content-Type': 'application/json'}, mode: 'cors', cache: 'default' } ) fetch(myRequest).then(function(response) { //... });
async function -MDN
await -MDNapp
async function f1() { var res = await requestPromise('GET', 'path/to/api'); console.log(res) } f1();
function sleep (time) { return new Promise(function (resolve, reject) {setTimeout(resolve, time)}) } var start = async function () { for (var i = 1; i <= 10; i++) { console.log(`當前是第${i}次等待..`); await sleep(1000); } }; start();
感受是 async/await 到來以前的過渡方案cors
const co=require('co') //let begin = new Date(); co(function* (){ let buyed = yield buySomething(); //console.log(buyed ,new Date() - begin); let cleaned = yield clean(); //console.log(cleaned ,new Date() - begin); let cook_and_wash = yield [cook(),wash()]; //console.log(cook_and_wash ,new Date() - begin); let eated = yield eat(); //console.log(eated,new Date() - begin); });
參考
XMLHttpRequest -MDN
使用 Promise - MDN
How do I promisify native XHR? - starkoverflow
深刻理解ES7的async/await
fetch-MDN
Request-MDN
async function -MDN
await -MDN
RxJS 中文文檔
Promises/A+