应用Promise封装Ajax实践

栏目: jQuery · 发布时间: 6年前

内容简介:先看看axios如何实现的。
应用Promise封装Ajax实践

: axios在项目中经常使用,但有次面试让我把ajax封装成axios形式,当时居然没写出来。看来还是不能停留在使用的表层。 回来研究promise觉得也并不是很难,关键是掌握Promise A+规范以及Promise写法。

先看看axios如何实现的。

axios部分源码分析:

axios 的自我介绍: Promise based HTTP client for the browser and node.js 即:

我,axios,就是基于Promise,服务于浏览器和node.js的的HTTP客户端。

下面重点看我想了解的ajax部分。

axios中的adapters模块

The modules under adapters/ are modules that handle dispatching a request and settling a returned Promise once a response is received.

此模块主要处理分发请求,并在返回的Promise一旦有响应被接收的情况下进行处理。

源码中查看: axios/lib/adapters/xhr.js 有这样一段让我眼前一亮:

module.exports = function xhrAdapter(config) {
 return new Promise(function dispatchXhrRequest(resolve, reject) {
 })
}
复制代码

找到promise大本营了!继续看源码,接下来就是Promise内部处理ajax重要的 open , onreadystatechange , send 几处实现,照样循规蹈矩,挑出来看:

// =>...omit config...
  // step1=>
  var request = new XMLHttpRequest();
  // step2=>
  request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);
  // step3=>
  request.onreadystatechange = function handleLoad() {
    if (!request || request.readyState !== 4) {
      return;
    }
  
    // The request errored out and we didn't get a response, this will be
    // handled by onerror instead
    // With one exception: request that using file: protocol, most browsers
    // will return status as 0 even though it's a successful request
    if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
      return;
    }
  
    // Prepare the response
    var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
    var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
    var response = {
      data: responseData,
      status: request.status,
      statusText: request.statusText,
      headers: responseHeaders,
      config: config,
      request: request
    };
  
    settle(resolve, reject, response);
    // Clean up request
    request = null;
  };
  // =>...omit handle process...
  // step4=>
  request.send(requestData);
复制代码

以上只是ajax的实现,但核心的then链式调用并没有实现,真正的实现来看 axios/lib/core/settle.js 下的settle方法:

/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*/
module.exports = function settle(resolve, reject, response) {
 var validateStatus = response.config.validateStatus;
 if (!validateStatus || validateStatus(response.status)) {
   resolve(response);
 } else {
   reject(createError(
     'Request failed with status code ' + response.status,
     response.config,
     null,
     response.request,
     response
   ));
 }
};
复制代码

关键的 resolvereject 解决后,按照规定(Promise A+ 规范 )

promise必须提供then方法来存取它当前或最终的值或者原因。

此时可以根据 promise.then(onFulfilled, onRejected) ,利用其中的两个方法对返回做处理。 以上已经基本实现了ajax的功能。

下面仿照axios的思想封装自己的promise_ajax

初步实现自己的P_ajax

function pajax({
    url= null,
	method = 'GET',
	dataType = 'JSON',
	async = true}){
	return new Promise((resolve, reject) => {
		let xhr = new XMLHttpRequest()
		xhr.open(method, url, async)
		xhr.responseType = dataType
		xhr.onreadystatechange = () => {
			if(!/^[23]\d{2}$/.test(xhr.status)) return
			if(xhr.readyState === 4) {
				let result = xhr.responseText
				resolve(result)
			}
		}
		xhr.onerror = (err) => {
			reject(err)
		}
		xhr.send()
	})
}
复制代码

默认调用JSON格式并测试成功

ajax({
    url:'./test.json',
    method: 'get'
}).then((result)=>{
    console.log(result)
},(err)=>{

})
复制代码

升级优化

针对不同请求类型,文件类型,做不同的处理

  • 添加判断请求类型,请求为get时,针对缓存做不同处理 cache为false即不设置缓存,利用最简单的加 _***解决,***为随机数
// 判断请求类型是否为GET
let isGet = /^(GET|DELETE|HEAD)$/i.test(method)
// 判断url有没有?,有的话就添加&
let symbol = url.indexOf('?')>-1 ? '&' : '?'
// GET系列请求才处理cache
if(isGet){
    !cache ? url+= `${symbol}_${Math.random()}`: null
}
复制代码
  • 根据返回类型对result做不同处理
let result = xhr.responseText
    // 根据dataType即不同的文件类型,对返回的内容做处理 
    switch(this.dataType.toUpperCase()){
        case 'TEXT':
        case 'HTML':
            break;
        case 'JSON':
            result = JSON.parse(result)
            break;
        case 'XML':
            result = xhr.responseXML
    }   
复制代码
  • 处理data 当data为对象时转化为str,方面get请求传参
function formatData(data){
       if(Object.prototype.toString.call(data)==='[object Object]'){
           let obj = data
           let str = ''
           for(let key in obj){
               if(obj.hasOwnProperty(key)){
                   str+=`${key}=${obj[key]}&`
               }
           }
           // 去掉最后多加的&
           str = str.replace(/&$/g,'')
           return str
       }
   }
   if(data !== null){
       data = formatData(data)
       if(isGet){
           url += symbol + data
           data = null
       }
   }
复制代码

简单测试结果:

pajax({
        url:'./test.json',
        method: 'get',
        cache: false,
        data:{
    	    name:'jyn',
            age:20
        }
	}).then((result)=>{
	    console.log(result)
    },(err)=>{
        console.log(err)
    })
复制代码

运行结果为: Request URL: http://localhost:63342/june/HTTP_AJAX/test.json?_0.6717612341262227?name=jyn&age=20 目前靠谱,且 then 方法也能获取到文件数据。 cache设置为false时,每次刷新获取都是200,不走304,功能正常。

以上,基于Promise的简易ajax就完工大吉啦!

Author: Yanni Jia

Nickname: 非常兔

Reference: axios源码:https://github.com/axios/axios


以上所述就是小编给大家介绍的《应用Promise封装Ajax实践》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python灰帽子

Python灰帽子

[美] Justin Seitz / 丁赟卿 译、崔孝晨 审校 / 电子工业出版社 / 2011-3 / 39.00元

《Python灰帽子》是由知名安全机构Immunity Inc的资深黑帽Justin Seitz主笔撰写的一本关于编程语言Python如何被广泛应用于黑客与逆向工程领域的书籍。老牌黑客,同时也是Immunity Inc的创始人兼首席技术执行官(CTO)Dave Aitel为这本书担任了技术编辑一职。书中绝大部分篇幅着眼于黑客技术领域中的两大经久不衰的话题:逆向工程与漏洞挖掘,并向读者呈现了几乎每个......一起来看看 《Python灰帽子》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换