ES6标准下的ajax封装

首先定义API接口

  • url:字符串类型,提交的网络地址
  • data:对象类型,提交的表单数据
  • type:提交的方法类型:GET或者POST,,默认为GET
  • method:使用的方法,
function Ajax(url = '', data = {}, type = 'GET', method = 'fetch'){
  // ...
}

整理表单数据

如果请求提交的方式为GET,我们就需要将表单数据拼接成形如“a=12&b=10”格式的字符串,并附加在url尾部。
如果请求提交的方式为POST,我们只需要使用JSON.stringify()方法,将表单数据转换成JSON格式对象即可。

type = type.toUpperCase()
let sendData

if (type == 'GET') {
  let _data = []
  Object.keys(data).forEach(key => {
    _data.push(key + '=' + data[key])
  })
  url = url + '?' + _data.join('&')
} else {
  sendData = JSON.stringify(data)
}

Object.keys()

ES5引入的一个方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历的属相的键名。
我们可以使用Object.keys(data)来获得表单数据对象所有可遍历的属性名数组。

arr.forEach()

用于遍历数组的成员

创建ajax提交对象

如果使用fetch方法,需要浏览器支持fetch方法

fetch
JavaScript 通过XMLHttpRequest(XHR)来执行异步请求,这个方式已经存在了很长一段时间。虽说它很有用,但它不是最佳API。它在设计上不符合职责分离原则,将输入、输出和用事件来跟踪的状态混杂在一个对象里。而且,基于事件的模型与最近JavaScript流行的Promise以及基于生成器的异步编程模型不太搭(事件模型在处理异步上有点过时了——译者注)。

新的 Fetch API打算修正上面提到的那些缺陷。 它向JS中引入和HTTP协议中同样的原语(即Fetch——译者注)。具体而言,它引入一个实用的函数fetch()用来简洁捕捉从网络上检索一个资源的意图。

Fetch 提供了对 Request 和 Response (以及其他与网络请求有关的)对象的通用定义。使之今后可以被使用到更多地应用场景中:无论是service workers、Cache API、又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式。

它还提供了一种定义,将 CORS 和 HTTP 原生的头信息结合起来,取代了原来那种分离的定义。

Fetch API是W3C的正式标准,被Firefox 39(Nightly版)以及Chrome 42(开发版)支持。在github上,有基于低版本浏览器的兼容实现

示例代码

// Simple response handling

fetch('/some/url').then(function(response) {



}).catch(function(err) {

    // Error :(

});

// Chaining for more "advanced" handling

fetch('/some/url').then(function(response) {

    return //...

}).then(function(returnedValue) {

    // ...

}).catch(function(err) {

    // Error :(

});

具体实现

let reqConfig = {
  credentials: 'include',
  method: type,
  headers: {
    'Accept': 'application/json',
    'Content-type': 'application/json'
  },
  mode: 'cors',
  cache: 'force-cache'
}

try {
  const response = fetch(url, reqConfig)
  const responseJson = response.json()

  return responseJson
} catch(error) {
  throw new Error(error)
}

如果使用传统的ajax方法

let reqObj

if (window.XMLHttpRequest) {
  reqObj = new XMLHttpRequest()
} else {
  reqObj = new ActiveXObject('Microsoft.XMLHTTP')
}

reqObj.open(type, url, true)
reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
reqObj.send(sendData)

reqObj.onreadystatechange = () => {
  if (reqObj.readyState == 4) {
    if (reqObj.status == 200) {
      let res = reqObj.response
      if (typeof res !== 'object') {
        res = JSON.parse(res)
      }
      return res
    } else {
      return reqObj
    }
  }
}

####采用ES6异步编程解决方案

Promise

Promise是ES6标准中提供的一种异步编程解决方案。当我们采用异步的方式发出一个ajax请求之后,系统不会等待请求响应,而是继续往下执行。一般我们采用回调的方式,当收到服务端响应之后,系统才会执行相应的回调函数。
Promise简单来说就是一个容器,容器内部保存着某个未来才会执行的事件。
Promise内部维护着一个状态机,总共有三种状态:Pending(进行中)、Fulfilled(已完成)、Rejected(已失败)。我们可以使用reject()resolve()来更改状态。

var promise = new Promise(function(resolve, reject) {
  /// ...

  if () { /* 如果异步操作执行成功 */
    // 将Promise对象的状态从“未完成”变为“成功”
    resolve(something)
  } else {/* 否则异步操作执行失败 */
    // 将Promise对象的状态从“未完成”变为“失败”
    reject(something)
  }
})

resolve和reject函数中的参数会自动传递给回调函数

promise.then(function(something) {
  // ...
  console.log(something)
})

我们可以采用链式then指定一组按照次序调用的回调函数

promise.then(function(something1) {
  // ...
  return promise(something2)
}).then(function(something2) {

})

因此,ajax异步处理过程可以改写为

return new Promise((resolve, reject) => {
  let reqObj

  if (window.XMLHttpRequest) {
    reqObj = new XMLHttpRequest()
  } else {
    reqObj = new ActiveXObject('Microsoft.XMLHTTP')
  }

  reqObj.open(type, url, true)
  reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
  reqObj.send(sendData)

  reqObj.onreadystatechange = () => {
    if (reqObj.readyState == 4) {
      if (reqObj.status == 200) {
        let res = reqObj.response
        if (typeof res !== 'object') {
          res = JSON.parse(res)
        }
        resolve(res)
      } else {
        reject(reqObj)
      }
    }
  }
})

async

ES2017标准引入了async函数,使得异步操作变得更加方便。async函数会返回一个Promise对象。

async function getUserInfo(userid){
  let userinfo = await getJson(...)

  return userinfo
}

await命令后面是一个Promise对象,如果不是,会被转成一个resolve的Promise对象

####完整代码

async function Ajax(url = '', data = {}, type = 'GET', method = 'fetch'){
  // 整理表单数据
  type = type.toUpperCase()
  let sendData

  if (type == 'GET') {
    let _data = []
    Object.keys(data).forEach(key => {
      _data.push(key + '=' + data[key])
    })
    url = url + '?' + _data.join('&')
  } else {
    sendData = JSON.stringify(data)
  }

  // 创建ajax提交对象

  if (window.fetch && method == 'fetch') {
    let reqConfig = {
      credentials: 'include',
      method: type,
      headers: {
        'Accept': 'application/json',
        'Content-type': 'application/json'
      },
      mode: 'cors',
      cache: 'force-cache'
    }

    try {
      const response = await fetch(url, reqConfig)
      const responseJson = await response.json()

      return responseJson
    } catch(error) {
      throw new Error(error)
    }
  } else {
    return new Promise((resolve, reject) => {
      let reqObj

      if (window.XMLHttpRequest) {
        reqObj = new XMLHttpRequest()
      } else {
        reqObj = new ActiveXObject('Microsoft.XMLHTTP')
      }

      reqObj.open(type, url, true)
      reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
      reqObj.send(sendData)

      reqObj.onreadystatechange = () => {
        if (reqObj.readyState == 4) {
          if (reqObj.status == 200) {
            let res = reqObj.response
            if (typeof res !== 'object') {
              res = JSON.parse(res)
            }
            resolve(res)
          } else {
            reject(reqObj)
          }
        }
      }
    })
  }

}

作为NodeJS的一个模块

export default async(url = '', data = {}, type = 'GET', method = 'fetch'){
  // 整理表单数据
  type = type.toUpperCase()
  let sendData

  if (type == 'GET') {
    let _data = []
    Object.keys(data).forEach(key => {
      _data.push(key + '=' + data[key])
    })
    url = url + '?' + _data.join('&')
  } else {
    sendData = JSON.stringify(data)
  }
  // 创建ajax提交对象

  if (window.fetch && method == 'fetch') {
    let reqConfig = {
      credentials: 'include',
      method: type,
      headers: {
        'Accept': 'application/json',
        'Content-type': 'application/json'
      },
      mode: 'cors',
      cache: 'force-cache'
    }

    try {
      const response = await fetch(url, reqConfig)
      const responseJson = await response.json()

      return responseJson
    } catch(error) {
      throw new Error(error)
    }
  } else {
    return new Promise((resolve, reject) => {
      let reqObj

      if (window.XMLHttpRequest) {
        reqObj = new XMLHttpRequest()
      } else {
        reqObj = new ActiveXObject('Microsoft.XMLHTTP')
      }

      reqObj.open(type, url, true)
      reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
      reqObj.send(sendData)

      reqObj.onreadystatechange = () => {
        if (reqObj.readyState == 4) {
          if (reqObj.status == 200) {
            let res = reqObj.response
            if (typeof res !== 'object') {
              res = JSON.parse(res)
            }
            resolve(res)
          } else {
            reject(reqObj)
          }
        }
      }
    })
  }

}

我们可以在使用的时候引入ajax模块

import ajax from 'ajax'

// 查询user_id为1的用户信息
ajax('/users', {
  user_id: 1
}).then(res => {
  console.log(res.username)
})

你可能感兴趣的:(JavaScript,nodejs)