Ajax подробно (рукописные jq и axios часть реализации)

Ajax

имея в виду:async javascript and xml 异步的js和xml

1. Нативная JS-операция Ajax

//一、创建Ajax实例
let xhr = new XMLHttpRequest();//IE下为ActiveObject对象
//二、打开请求: 发送请求之前的一些配置项
//1.HTTP METHOD:GET/POST/PUT/DELETE/HEAD/OPTIONS/TRACE/CONNECT/
//2.url:接口地址
//3.async:设置Ajax的同步异步,默认是异步
//4.user-name/user-pass用户名和密码,一般不用
xhr.open(method, url, async, [user-name], [user-pass])
//三、事件监听:一般监听的都是readystatechange事件(Ajax状态改变事件),基于这个事件可以获取服务器返回的响应头响应主体
xhr.onreadystatechange = () => {
	if(xhr.readyState === 4 && xhr.status === 200){
		console.log(xhr.responseText);
	}
};
//四、发送Ajax请求:从这步开始,当前Ajax任务开始,如果Ajax是同步的,后续代码不会执行,要等到Ajax状态成功后再执行
xhr.send([请求主体内容])

2. О методе HTTP-запроса:

ПОЛУЧИТЬ: получить данные с сервера

POST: отправить данные на сервер

УДАЛИТЬ: удалить что-то на стороне сервера

PUT: сохранить что-то на сервере

HEAD: хотите получить только информацию заголовка ответа, возвращаемую сервером, а не содержимое тела ответа

ПАРАМЕТРЫ: Обычно используется для отправки исследовательского запроса на сервер.Если информация возвращается, это означает, что текущий клиент и сервер установили соединение и могут продолжать выполнять другие запросы.

TRACE: Когда axios библиотеки классов Ajax выполняет междоменные запросы на основе междоменных запросов, она сначала отправляет OPTIONS для попыток обнаружения. Если сервер может быть подключен, другие запросы будут продолжать отправляться.

Разница между GET и POST:

[Способ передачи информации на сервер отличается]

GET передает параметры через строку URL, POST передает тело запроса

[GET]
xhr.open('GET', '/tmp/list?xxx=xxx&xxx=xxx')

[POST]
xhr.send('xxx=xxx')
(一般是url-encode格式)
[GET небезопасен, POST относительно безопасен]

Поскольку GET передает информацию на сервер на основе «параметров передачи вопросительного знака», ее легко перехватить путем взлома URL-адреса, а сообщение передается на основе тела запроса.

[GET создаст неуправляемый кеш, POST — нет]

Неконтролируемая: это автономная память браузера, и JS не может ею управлять. решение

xhr.open('GET', `/temp/list?lx=1000&_=${Math.random()}`);
Другие отличия:
  • GET безвреден, когда браузер отступает, а POST снова отправляет запрос
  • Запросы GET будут активно кэшироваться браузером, а запросы POST — нет, если только они не будут установлены вручную.
  • Параметры запроса GET полностью сохраняются в истории браузера, а POST — нет.
  • Запросы GET могут быть закодированы только в URL-адресе, а POST поддерживает несколько методов кодирования.

Три, состояние готовности Ajax

0 => unsious только что начал создавать XHR, еще не отправлено

1 => OPENED выполнил операцию открытия

2 => HEADERS_RESERVED Ajax был отправлен, и заголовки ответа были приняты клиентом

3 => Содержимое тела ответа LOADING возвращается

4 => DONE Тело ответа получено клиентом

4. Состояние кода состояния сети HTTP

По коду статуса можно наглядно отразить результат и причину текущего взаимодействия

1XX: Индикационная информация — указывает, что запрос принят и продолжает обрабатываться.

2XX: Успех — указывает, что запрос был успешно получен.

3XX: успешно, но перенаправлено

4XX: ошибка клиента

5XX: ошибка сервера.

Конкретные примеры:

200 OK: клиентский запрос выполнен успешно

206 Partial Content: клиент отправил запрос GET с заголовком Range, и сервер выполнил его.

301 Moved Permamently: навсегда перемещен на новый URL

302 Found: Временно перейдите на новый URL-адрес, когда сервер достигнет максимального количества одновременных запросов, он перенесет обработку сервера

304 Not Modified: сервер сообщает клиенту, что можно продолжать использовать исходный кеш, например CSS/JS/HTML/IMG, Ctrl+F5 304 аннулирование кеша.

400 Bad Request: у клиента есть синтаксическая ошибка, которую сервер не может понять

401 Неавторизованный: запрос не авторизован

403 Forbidden: доступ к запрошенной странице запрещен

404 не найдено: запрашиваемый ресурс не существует

413 Request Entity Too Large Ресурс контента, взаимодействующий с сервером, превышает максимальный размер.

500 Internal Server Error Ошибка сервера, исходный кеш все еще можно использовать

503 Service Unavailable

Пять, о свойствах и методах XHR

Содержимое тела ответа xhr.response

xhr.responseText Содержимое ответа представляет собой строку (документ JSON или XML).

xhr.responseXML Содержимое ответа в формате xml

Xhr.status вернул код состояния HTTP

Описание кода состояния xhr.statusText

xhr.timeout устанавливает время ожидания запроса

xhr.timeout = 1000
xhr.ontimeout = () => {
	console.log(‘请求超时’)
}

Разрешает ли xhr.withCredentials междоменное использование (false)

xhr.abort() принудительно прерывает запрос Ajax

xhr.abort();
xhr.onabort = () => {}

xhr.getAllResponseHeaders() Получить всю информацию заголовка ответа

xhr.getResponseHeader([key]) Например: xhr.getResponseHeader('date') — получить время сервера в заголовке ответа

xhr.open() открытый запрос URL

xhr.overrideMimeType() переопределяет тип MIME

xhr.send() отправляет запрос Ajax, параметр является объектом тела запроса

xhr.setRequestHeader() Установить пользовательскую информацию заголовка запроса (не может отображаться на китайском языке), которая должна быть установлена ​​после открытия

//小例子
xhr.onreadystatechange = () => {
	if(!/^(2|3)\d{2}$/.test(xhr.status))return;//证明服务器已经返回内容了
	if(xhr.readyState === 2){
		let time = xhr.getResponseHeader('date');
	}
	if(xhr.readyState === 4 && xhr.status === 200){
		JSON.parse(xhr.responseText);
	}
}

Шесть, разница между асинхронным и синхронным

асинхронный:

let xhr = new XMLHttpRequest();
xhr.open('GET', 'xxx', true);
xhr.onreadystatechange = () => {
	if(xhr.readyState === 2) {
		console.log(1);
	}
	if(xhr.readyState === 4) {
		console.log(2)
	} 
}
xhr.send(); 
console.log(3)
//3 1 2 

Синхронизировать:

let xhr = new XMLHttpRequest();
xhr.open('GET', 'xxx', false);
xhr.onreadystatechange = () => {
	if(xhr.readyState === 2) {
		console.log(1);
	}
	if(xhr.readyState === 4) {
		console.log(2)
	} 
}
xhr.send(); //任务开始,只要当前Ajax请求这件事没完成(readyState没到4),什么都不能做
console.log(3)
//2 3 为什么呢?
//由于是同步编程,主任务队列在状态没有变成4之前一直被Ajax请求占用,其他事件做不了。
//所以,只有readyState变成4才能执行方法。

let xhr = new XMLHttpRequest();
xhr.open('GET', 'xxx', false);
xhr.send(); //任务开始,只要当前Ajax请求这件事没完成(readyState没到4),什么都不能做
//现在状态已经为4
xhr.onreadystatechange = () => {
	if(xhr.readyState === 2) {
		console.log(1);
	}
	if(xhr.readyState === 4) {
		console.log(2)
	} 
}

console.log(3)
//3
//因此采用异步Ajax

Семь, Ajax в jQuery

/**
 * DATA:
 *	如果是GET请求是基于问号传参过去的
 *	如果是POST请求是基于请求主体传递过去的
 *	data的值可以是对象也可以是字符串(一般常用对象):
 *		如果是对象,jq会把对象转换为 xxx=xxx 的模式(x-www-form-urlencoded)
 * DATA-TYPE:预设置获取结果的数据格式 TEXT/JSON/JSONP/HTML/XML/SCRIPT(服务器返回给客户端的响应主体中的内容一般是字符串,
 *	而设置DATA-TYPE='json',jq会内部把获取的字符串转化为JSON格式的对象 => 它不影响服务器返回的结果,只是二次处理结果)
 * ASYNC:设置是否异步
 * CACHE:设置是否缓存,当设置FALSE,并且get请求,JQ会在请求的url地址末尾加随机数
 * SUCCESS:回调函数,当Ajax请求成功执行,JQ执行回调函数时把响应主体中获取的结果(二次处理)当做参数
 * ERROR: 请求失败后执行的回调函数
 */
$.ajax({
	url: 'xxx',
	method: 'GET',
	data: null,
	dataType: 'json',
	async: true,
	cache: true,
	success: (result, textStatus, xhr) => {},
	error: () => {}
})

Восемь, непобедимый почерк

Собственный пакет JS ajax (версия jQ)

~ function (window) {
  function AJAX(options) {
    return new AJAX.prototype.init(options);
  }
  function init(options = {}){
    let {
      url,
      method = 'GET',
      data = null,
      dataType = 'JSON',
      async = true,
      cache = true,
      success,
      error
    } = options;
    //=>MOUNT 把配置项挂载到实例上
    ['url', 'method', 'data', 'dataType', 'async', 'cache', 'success', 
    'error'].forEach(item => {
      this[item] = eval(item);
    });
  }
  
  AJAX.prototype = {
    constructor: AJAX,
    init,
    sendAjax(){
      this.handleCache();
      this.handleData();
      //send
      let {method, url, async, error, success} = this;
      //SEND发送请求
      let xhr = new XMLHttpRequest();
      xhr.open(method, url, async);
      xhr.onreadystatechange = () => {
        if(xhr.readyState === 4){
          if(!/^(2|3)\d{2}$/.test(xhr.status)){
            error && error(xhr.statusText, xhr)
          }
          //处理DATA-TYPE
          let result = this.handleDataType(xhr);
          success && success(result, xhr);
        }
      };
      xhr.send();
    },
    handleDataType(xhr) { 
      let dataType = this.dataType.toUpperCase(),
          result = xhr.responseText;
      switch (dataType) {
        case 'TEXT':
          break;
        case 'JSON':
          result = JSON.parse(result);
          break;
        case 'XML':
          result = xhr.responseXML;
          break;
      }  
      return result;    
    },
    handleCache() {
      let {url, method, cache} = this;
      if(/^GET$/i.test(method) && cache==false){
        url += `${this.check()}=${+(new Date())}`;
      }
    },
    handleData() {
      let {data, method} = this;
      if(!data) return;
      if(typeof data === 'object'){
        //如果是一个对象,我们把它转换为x-www-form-urlencoeded模式
        for(let key in data){
          if(data.hasOwnProperty(key)){
            str += `${key}=${data[key]}`;
          }
        }
        data=str.substring(0,str.length);
      }
      if(/^(GET|DELETE|HEAD|TRACE|OPTIONS)$/i.test(method)){
        this.url += `${this.check()}${data}`;
        this.data = null;
        return;
      }
      this.data = data; //POST处理方式
    },
    check() {
      return this.url.indexOf('?')>-1?'&':'?';
    }
  }
  init.prototype = AJAX.prototype;

  window.ajax = AJAX;
}(window)

На основе линии Promise и Ajax с нативной рукой JS (версия axios)

~ function (window) {
  //设置默认的参数配置项  
  let _default = {
    method: 'GET',
    url: '',
    baseURL: '',
    headers: {},
    dataType: 'JSON',
    data: null, //POST系列
    params: null, //GET系列
    cache: true
  };
  //基于Promise设计模式管理Ajax
  let ajaxPromise = function axios() {
    let {
      url,
      baseURL,
      data,
      dataType,
      headers,
      cache,
      params
    } = options;
    //=>把传递的参数进一步进行处理
    if(/^(GET|DELETE|HEAD|OPTIONS)$/.test(method)){
      //GET参数
      if(params) {
        url += `${ajaxPromise.check(url)}${ajaxPromise.formatData(params)}`
      }
      if(cache === false){
        url += `${ajaxPromise.check(url)}_=${+(new Date())}`
      }
      data= null;//GET系列请求主体为空
    }else{
      //POST系列
      if(data){
        data = ajaxPromise.formatData(data);
      }
    }
    //=>基于Promise发送Ajax
    return new Promise((resolve, reject) => {
      let xhr = new XMLHttpRequest();
      xhr.open(method, `${baseURL}${url}`);
      if(headers != null && typeof headers === 'object'){
        for(let attr in headers){
          if(headers.hasOwnProperty(attr)){
            let val = headers[attr];
            if(/[\u4e00-\u9fa5]/.test(val)){
              val = encodeURIComponent(val);
            }
            xhr.setRequestHeader(attr, headers[attr]);
          }
        }
      }
      //=>如果headers存在,我们需要设置请求头
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4){
          if(/^(2|3)\d{2}$/.test(xhr.status)){
            let result = xhr.responseText;
            dataType = dataType.toUpperCase();
            dataType === 'JSON'?result = JSON.parse(result):(dataType === 'XML'?result = xhr.responseXML : null);
            resolve(result, xhr);
            return;
          }
          reject(xhr.statusText, xhr);
        }
      }
      xhr.send(data);
    })
  }

  ajaxPromise.defaults = _default;

  ajaxPromise.formatData = function formatData(){
    let str = ``;
    for(let attr in obj) {
      if(obj.hasOwnProperty(attr)){
        str += `${attr}=${obj[attr]}&`;
      }
      return str.substring(0, str.length-1)
    }
  }

  ajaxPromise.check = function check(url){
    return url.indexOf('?')>-1?'&':'?';
  }

  //GET系列 
  ['get', 'delete', 'head', 'options'].forEach(item => {
    ajaxPromise[item] = (url, options = {}) => {
      options = {
        ..._default,
        ...options, 
        url, 
        method: item.toUpperCase()
      };
      return ajaxPromise(options);
    }
  })
  //POST系列
  ['post', 'put', 'patch'].forEach(item => {
    ajaxPromise[item] = (url, data = {}, options = {}) => {
      options = {
        ..._default,
        ...options, 
        url, 
        method: item.toUpperCase(),
        data
      };
      return ajaxPromise(options);
    }
  })

  window.ajaxPromise = ajaxPromise;
}(window)

Небольшое резюме по Аяксу, надеюсь всем поможет!