Open youngwind opened 8 years ago
我们使用jquery的时候,经常用到的是$.ajax,可以发各种异步请求。不过这次我们先来实现一个更简单的方法,$.getJSON:向服务器发起一个get请求,获取相应的json数据。
我们先来分析一下有哪几个方面需要注意:
一个简单的XHR demo
// 创建一个请求对象 var client = new XMLHttpRequest(); // 启动请求(注意,此处请求仍未发送,只是准备好而已) client.open('get','https://api.github.com/users/youngwind/starred'); // 发送请求 client.send();
我们如何知道监控请求的进度,知道它什么时候完成呢?xhr对象有个readyState属性,每当请求阶段改变的时候,readyState都会发生改变,从而触发readystatechange事件。代码如下:
T.getJSON = function (url, cb) { // 创建一个请求对象 var client = new XMLHttpRequest(); // 下面几行代码的顺序很重要 // 必须是先open,然后各种set,最后是send,否则会报错 client.open('get', url); client.setRequestHeader("Accept", "application/json"); client.responseType = 'json'; client.send(); client.onreadystatechange = function () { if (this.readyState === 4) { if (this.status >= 200 && this.status < 300 || xhr.status == 304) { cb && cb(this.response); } else { console.log('error', this.status); } } } };
ok,目前为止,我们已经成功实现:创建一个xhr对象,向服务器请求json数据,请求成功后传给回调函数进行处理。但是,问题在于,用callback的方法进行异步回调的处理太low了吧。 jquery在1.5.0版本之后开始引入deferred对象用于解决回调问题,可以参考这里。解决回调的方法有很多,比如 #49 #62 , 不妨我们用promise实现一个吧,因为ES6标准都已经原生支持promise了。
一个promise的简单demo
var promise = new Promise(function(resolve, reject){ if(/*异步操作成功*/) { resolve(value); } else { reject(error); } })
所以,我们需要将T.getJSON封装成返回一个promise对象,这样就能用.then了。
T.getJSON = function (url) { var promise = new Promise(function (resolve, reject) { // 创建一个请求对象 var client = new XMLHttpRequest(); client.open('get', url); client.setRequestHeader("Accept", "application/json"); client.responseType = 'json'; client.send(); client.onreadystatechange = function () { if (this.readyState === 4) { if (this.status >= 200 && this.status < 300 || xhr.status == 304) { resolve(this.response); } else { reject(this.response); } } } }); return promise; };
使用例子:
T.getJSON('https://api.github.com/users/youngwind/starred') .then(function(res){ console.log(res); });
如果我们有这样的需求:请求A、B、C都完成之后再调用回调函数,又或者这样的需求:请求A、B、C任意一个率先完成都会调用回调函数,那该怎么处理呢?这种情况使用promise.all和promise.race可以轻松解决。
/** * 请求json数据 * @param url {string}/{Array} 请求url(数组) * @param isAll {boolean} 如果url是数组,那么此状态位有用,默认为true * 如果为true,则所有请求都结束之后再返回,传递给resolve的数据是所有请求返回数据构成的数组 * 如果为false,则任一请求结束之后都会返回,传递给resolve的数据是那个率先完成的请求返回的数据 * @returns {Promise} */ T.getJSON = function (url, isAll) { if (!Array.isArray(url)) { return generatePromiseXHR(url); } var promises = url.map(function (subUrl) { return generatePromiseXHR(subUrl); }); if (isAll) { return Promise.all(promises); } else { return Promise.race(promises); } function generatePromiseXHR(url) { var promise = new Promise(function (resolve, reject) { // 创建一个请求对象 var client = new XMLHttpRequest(); client.open('get', url); client.setRequestHeader("Accept", "application/json"); client.responseType = 'json'; client.send(); client.onreadystatechange = function () { if (this.readyState === 4) { if (this.status >= 200 && this.status < 300 || xhr.status == 304) { resolve(this.response); } else { reject(this.response); } } }; }); return promise; } };
参考链接: http://es6.ruanyifeng.com/#docs/promise
问题
我们使用jquery的时候,经常用到的是$.ajax,可以发各种异步请求。不过这次我们先来实现一个更简单的方法,$.getJSON:向服务器发起一个get请求,获取相应的json数据。
分析
我们先来分析一下有哪几个方面需要注意:
XMLHttpRequest
一个简单的XHR demo
我们如何知道监控请求的进度,知道它什么时候完成呢?xhr对象有个readyState属性,每当请求阶段改变的时候,readyState都会发生改变,从而触发readystatechange事件。代码如下:
promise
ok,目前为止,我们已经成功实现:创建一个xhr对象,向服务器请求json数据,请求成功后传给回调函数进行处理。但是,问题在于,用callback的方法进行异步回调的处理太low了吧。 jquery在1.5.0版本之后开始引入deferred对象用于解决回调问题,可以参考这里。解决回调的方法有很多,比如 #49 #62 , 不妨我们用promise实现一个吧,因为ES6标准都已经原生支持promise了。
一个promise的简单demo
所以,我们需要将T.getJSON封装成返回一个promise对象,这样就能用.then了。
使用例子:
promise.all与promise.race
如果我们有这样的需求:请求A、B、C都完成之后再调用回调函数,又或者这样的需求:请求A、B、C任意一个率先完成都会调用回调函数,那该怎么处理呢?这种情况使用promise.all和promise.race可以轻松解决。
参考链接: http://es6.ruanyifeng.com/#docs/promise