逐步了解Ajax和Promise
Ajax
AJAX 就是用 JS 发送请求和接收响应
AJAX 是异步的 JS 和 XML(Asynchronous JavaScript And XML),目前我们一般使用 JSON 代替 XML。AJAX 主要用于在不刷新页面的情况下向浏览器发起请求并接受响应,最后局部更新页面,它最核心的概念是 XMLHttpRequest 对象,该对象可以发起 HTTP 请求,我们可以监听其 readyState 的变化获得响应。
你可以使用AJAX最主要的两个特性做下列事:
- 在不重新加载页面的情况下发送请求给服务器。
- 接受并使用从服务器发来的数据。
JS 中发送一个请求到成功得到响应的时间在几百毫秒到一两秒之间。
使用 AJAX 的四个步骤:
1. 创建 XMLHttpRequest 对象
通过XMLHttpRequest()
构造函数用于初始化一个 XMLHttpRequest
实例对象
var xhr = new XMLHttpRequest()
2.与服务器建立连接 调用对象的 open 方法 .open(method, url)
通过 XMLHttpRequest
对象的 open()
方法与服务器建立连接
xhr.open(method, url, [async][, user][, password])
参数说明:
method
:表示当前的请求方式,常见的有GET
、POST
url
:服务端地址async
:布尔值,表示是否异步执行操作,默认为true
user
: 可选的用户名用于认证用途;默认为`nullpassword
: 可选的密码用于认证用途,默认为`null
3. 监听对象的 onreadystatechange 事件(在事件处理函数里操作 CSS / JS / HTML / responseXML / JSON.parse)
onreadystatechange
事件用于监听服务器端的通信状态,主要监听的属性为XMLHttpRequest.readyState
,
关于XMLHttpRequest.readyState
属性有五个状态,如下图显示
只要 readyState
属性值一变化,就会触发一次 readystatechange
事件
XMLHttpRequest.responseText
属性用于接收服务器端的响应结果
举个例子:
const request = new XMLHttpRequest() request.onreadystatechange = function(e){ if(request.readyState === 4){ // 整个请求过程完毕 if(request.status >= 200 && request.status <= 300){ console.log(request.responseText) // 服务端返回的结果 }else if(request.status >=400){ console.log("错误信息:" + request.status) } } } request.open('POST','http://xxxx') request.send()
4. 调用对象的 send 方法(发送请求)
通过 XMLHttpRequest
对象的 send()
方法,将客户端页面的数据发送给服务端
xhr.send([body])
body
: 在 XHR
请求中要发送的数据体,如果不传递数据则为 null
如果使用GET
请求发送数据的时候,需要注意如下:
- 将请求数据添加到
open()
方法中的url
地址中 - 发送请求数据中的
send()
方法中参数设置为null
const ajax = (method, url, data, success, fail) => { var request = new XMLHttpRequest() request.open(method, url); request.onreadystatechange = function () { if(request.readyState === 4) { if(request.status >= 200 && request.status < 300 || request.status === 304) { success(request) }else{ fail(request) } } }; request.send(); }
加载
在设置正确的 Content-Type 的前提下,使用 AJAX 可以轻量级地请求 HTML / CSS / JavaScript / XML / JSON 等内容,只要知道怎么解析这些内容,就可以使用这些内容。解析方法如下:
- 得到 CSS 之后生成 style 标签
- 得到 JS 之后生成 script 标签
- 得到 HTML 之后使用 innerHTML 和 DOM API
- 得到 XML 之后使用 reponseXML 和 DOM API
- 得到 JSON 之后使用 JSON.parse
- 不同类型的数据有不同类型的解析方法
用 AJAX 加载 CSS
getCSS.onclick = () => { const request = new XMLHttpRequest(); request.open("GET", "/style.css"); //readyState = 1 request.onreadystatechange = () => { //下载完成,但不知道是成功(2xx) 还是失败(4xx 5xx) if (request.readyState === 4) { if (request.status >= 200 && request.status < 300) { //创建 style 标签 const style = document.createElement("style"); //填写 style 内容 style.innerHTML = request.response; //插入到 head 里面 document.head.appendChild(style); } else { alert("加载 CSS 失败"); } } }; request.send(); //readyState = 2 };
用 AJAX 加载 JS
getJS.onclick = () => { const request = new XMLHttpRequest(); request.open("GET", "/2.js"); request.onreadystatechange = () => { if (request.readyState === 4) { if (request.status >= 200 && request.status < 300) { //创建 script 标签 const script = document.createElement("script"); //填写 script 内容 script.innerHTML = request.response; //插入到 body 里面 document.body.appendChild(script); } else { alert("加载 JS 失败"); } } }; request.send(); };
用 AJAX 加载 HTML
getHTML.onclick = () => { const request = new XMLHttpRequest(); request.open("GET", "/3.html"); request.onreadystatechange = () => { if (request.readyState === 4) { if (request.status >= 200 && request.status < 300) { //创建 div 标签 const div = document.createElement("div"); //填写 div 内容 div.innerHTML = request.response; //插入到 body 里面 document.body.appendChild(div); } else { alert("加载 HTML 失败"); } } }; request.send(); };
用 AJAX 加载 XML
getXML.onclick = () => { const request = new XMLHttpRequest(); request.open("GET", "/4.xml"); request.onreadystatechange = () => { if ( request.readyState === 4 && request.status >= 200 && request.status < 300 ) { //获取 XML 的 DOM 对象 const dom = request.responseXML; //获取内容 const text = dom.getElementsByTagName("warning")[0].textContent; //消除内容中的'回车' console.log(text.trim()); } }; request.send(); };
用 AJAX 加载 JSON
getJSON.onclick = () => { const request = new XMLHttpRequest(); request.open("GET", "/5.json"); request.onreadystatechange = () => { if ( request.readyState === 4 && request.status >= 200 && request.status < 300 ) { console.log(request.response); const object = JSON.parse(request.response); //字符串转换为对象(反序列化) console.log(object); myName.textContent = object.name; } }; request.send(); };
学习链接
例子
封装
通过上面对XMLHttpRequest
对象的了解,下面来封装一个简单的ajax
请求
//封装一个ajax请求 function ajax(options) { //创建XMLHttpRequest对象 const xhr = new XMLHttpRequest() //初始化参数的内容 options = options || {} options.type = (options.type || 'GET').toUpperCase() options.dataType = options.dataType || 'json' const params = options.data //发送请求 if (options.type === 'GET') { xhr.open('GET', options.url + '?' + params, true) xhr.send(null) } else if (options.type === 'POST') { xhr.open('POST', options.url, true) xhr.send(params) //接收请求 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { let status = xhr.status if (status >= 200 && status < 300) { options.success && options.success(xhr.responseText, xhr.responseXML) } else { options.fail && options.fail(status) } } } }
使用方式如下
ajax({ type: 'post', dataType: 'json', data: {}, url: 'https://xxxx', success: function(text,xml){//请求成功后的回调函数 console.log(text) }, fail: function(status){////请求失败后的回调函数 console.log(status) } })
Promise
大佬文章异步解决方案
什么是异步什么是同步
- 同步:如果能直接拿到结果就是同步
- 异步:不能直接拿到结果
异步举例
- 以AJAX为例
request.send()之后并不能直接得到response,必须等到readystate变为4之后,浏览器才会回头调用request.onreadystatechange函数。 - 回调callback
写给自己用的函数,不是回调,写给别人用的函数是回调。比如request.onreadystatechange就是我写给浏览器调用的函数。
异步和回调的关系
- 关联
异步任务需要在得到结果时通知js来取,这时我们可以给js留一个函数地址,异步任务完成时浏览器调用该函数地址,同时把结果作为参数传给该函数,这里的函数是我写给浏览器调用的,所以时回调函数。 - 区别
异步任务需要用到回调函数来通知结果 但回调函数不一定只用在异步任务里,也可以用到同步任务中 arr.forEach(n=>console.log(n)) 就是同步回调
判断同步异步
- 如果一个函数的返回值处于
1.setTimeout
2.AJAX(即XMLHttpRequest)
3.addEventListener 这三个值的内部就是异步函数。
注意:不要把AJAX设置成同步的,这样会使页面卡住
总结
- 异步任务不能拿到结果
- 于是传一个回调给异步任务
- 异步完成时调用回调
- 调用时把结果作为参数
promise(解决异步任务的两个结果:成功或失败)
解决异步任务的回调问题
- 规范回调的名字或顺序
- 拒绝回调地狱,让代码的可读性更高
- 很方便的捕获任务
以AJAX为例解释promise
核心就是 这一句话
总结
- 第一步
1.return new Promise((resolve,reject)=>{...})
2.任务成功调用resolve(result)
3.任务失败调用reject(onerror)
4.resolve和reject会再去调用成功和失败函数 - 第二步
使用.then(success,fail)传入成功和失败函数
封装AJAX的缺点
- .post无法上传数据(request.send可以上传)
- 不能设置请求头(request.setRequestHeader(key,value))
解决方法
- jQuery.ajax
- axios(目前最新的ajax库)
代码示例
网络异常,图片无法展示|
优点:自动调用JSON.parse,请求拦截器;响应拦截器
Promise的使用
第一步
创建一个promise对象、可以使用new
来调用Promise
的构造器来进行实例化
return new Promise((resolve,reject)=>{ // 异步处理 // 处理结束后、调用resolve 或 reject })
- 任务成功时调用
resolve(成功)
任务失败时调用reject(失败)
- resolve 和 reject 都只接受一个参数
第二步
第一步构造出来的promise对象,含有一个 .then() 函数属性使用promise.then()
实例方法,设置其值在 resolve(成功) / reject(失败)时调用的回调函数
promise.then(onFulfilled, onRejected)
- resolve(成功)时
onFulfilled
会被调用 - reject(失败)时
onRejected
会被调用
举例
使用promise来发送网络请求
function getURL(URL) { return new Promise(function (resolve, reject) { var req = new XMLHttpRequest(); req.open('GET', URL, true); req.onload = function () { if (req.status === 200) { resolve(req.responseText); } else { reject(req.statusText)); } }; req.onerror = function () { reject(req.statusText)); }; req.send(); }); } var URL = "http://xxx"; getURL(URL).then(function onFulfilled(value){ console.log(value); },function onRejected(error){ console.log(error); });
Promise还有更高级的用法,链式调用等等,以后在进行总结~