Ajax Fetch 和 Axios(持续更新中 …)
知识点梳理
AJAX 不是 JavaScript 的规范,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用 JavaScript 执行异步网络请求。
JavaScript 代码都是单线程执行的,由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现,回调函数不好看,不利于代码复用,而链式写法好处 逻辑统一、利于复用,所以出现 Primose Promise 有各种开源实现,在 ES6 中被统一规范,由浏览器直接支持。
async await 是 Promise 语法糖,使异步的逻辑书写标准的同步函数
Generator
原生 XHR
Ajax
AJAX 不是 JavaScript 的规范,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用 JavaScript 执行异步网络请求。
属性
描述
onreadystatechange
每当 readyState 属性改变时,就会调用该函数。
readyState
存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。0: 请求未初始化 1: 服务器连接已建立,open() 方法已调用,但是 send() 方法未调用 2: 请求已连接 send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到相应 3: 请求处理中 4: 请求已完成,且响应已就绪
status
200: “OK”404: 未找到页面
;(function() {
var xmlhttp
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp = new XMLHttpRequest()
} else {
// IE6, IE5 浏览器执行代码
xmlhttp = new ActiveXObject(‘Microsoft.XMLHTTP’)
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
console.log(xmlhttp.responseText)
}
}
xmlhttp.open(‘GET’, ‘http://www.runoob.com/try/ajax/ajax_info.txt’, true)
xmlhttp.send()
})()
Ajax 安全限制
浏览器的同源策略导致的。默认情况下,JavaScript 在发送 AJAX 请求时,URL 的域名必须和当前页面完全一致
跨域请求
通过 Flash 插件发送 HTTP 请求,这种方式可以绕过浏览器的安全限制,但必须安装 Flash,并且跟 Flash 交互。不过 Flash 用起来麻烦,而且现在用得也越来越少了。
通过在同源域名下架设一个代理服务器来转发,JavaScript 负责把请求发送到代理服务器
JSONP 它有个限制,只能用 GET 请求,并且要求返回 JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用 JavaScript 资源
CORS CORS 全称 Cross-Origin Resource Sharing,是 HTML5 规范定义的如何跨域访问资源。面这种跨域请求,称之为“简单请求”。简单请求包括 GET、HEAD 和 POST(POST 的 Content-Type 类型仅限 application/x-www-form-urlencoded、multipart/form-data 和 text/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足 90% 的需求
Promise
在 JavaScript 的世界中,所有代码都是单线程执行的。
由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现
function callback() {
console.log(‘Done’)
}
console.log(‘before setTimeout()’)
setTimeout(callback, 1000) // 1 秒钟后调用 callback 函数
console.log(‘after setTimeout()’)
链式写法的好处在于,先统一执行 AJAX 逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用 success 函数或 fail 函数。
古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在 JavaScript 中称为 Promise 对象。
使用 Promise 封装 ajax 简化异步处理
// ajax 函数将返回 Promise 对象:
function ajax(method, url, data) {
var request = new XMLHttpRequest()
return new Promise(function(resolve, reject) {
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
resolve(request.responseText)
} else {
reject(request.status)
}
}
}
request.open(method, url)
request.send(data)
})
}
var p = ajax(‘GET’, ‘/api/categories’)
p.then(function(text) {
// 如果 AJAX 成功,获得响应内容
}).catch(function(status) {
// 如果 AJAX 失败,获得响应代码
})
Promise 使用方法
;(function() {
console.time(‘doIt’)
const time1 = 300
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`)
console.timeEnd(‘doIt’)
})
})()
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n)
})
}
function step1(n) {
console.log(`step1 with ${n}`)
return takeLongTime(n)
}
function step2(n) {
console.log(`step2 with ${n}`)
return takeLongTime(n)
}
function step3(n) {
console.log(`step3 with ${n}`)
return takeLongTime(n)
}
Promise.all()
两个任务是可以并行执行的,用 Promise.all() 实现
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, ‘P1’)
})
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 6000, ‘P2’)
})
// 同时执行 p1 和 p2,并在它们都完成后执行 then:
Promise.all([p1, p2]).then(function(results) {
console.log(results) // 获得一个 Array: [‘P1’, ‘P2’]
})
Promise.race()
有些时候,多个异步任务是为了容错,只需要获得先返回的结果即可
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 3000, ‘P1’)
})
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 6000, ‘P2’)
})
// 同时执行 p1 和 p2,其中一个完成后执行 then:
Promise.race([p1, p2]).then(function(results) {
console.log(results) // // ‘P1’
})
async await
await
await 操作符用于等待一个 Promise 对象。它只能在异步函数 async function 中使用
await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理 (fulfilled),其回调的 resolve 函数参数作为 await 表达式的值,继续执行 async function。若 Promise 处理异常 (rejected),await 表达式会把 Promise 的异常原因抛出。
另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。
// 如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x)
}, 2000)
})
}
async function f1() {
var x = await resolveAfter2Seconds(10)
console.log(x) // 10
}
f1()
// 如果 Promise 处理异常,则异常值被抛出。
async function f3() {
try {
var z = await Promise.reject(30)
} catch (e) {
console.log(e) // 30
}
}
f3()
async
async function 声明用于定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。
一个返回的 Promise 对象会以 async function 的返回值进行解析 (resolved),或者以该函数抛出的异常进行回绝 (rejected)。
async 函数中可能会有 await 表达式,这会使 async 函数暂停执行,等待 Promise 的结果出来,然后恢复 async 函数的执行并返回解析值(resolved)。
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve(‘resolved’)
}, 2000)
})
}
async function asyncCall() {
console.log(‘calling’)
var result = await resolveAfter2Seconds()
console.log(result)
// expected output: ‘resolved’
}
asyncCall()
Generator
Fetch
Fetch 是一个现代的概念, 等同于 XMLHttpRequest。它提供了许多与 XMLHttpRequest 相同的功能,但被设计成更具可扩展性和高效性。
Fetch 是挂在在 window 下的
Fetch 的核心在于对 HTTP 接口的抽象,包括 Request,Response,Headers,Body,以及用于初始化异步请求的 global fetch。Fetch 还利用到了请求的异步特性——它是基于 Promise 的。
fetch(‘http://example.com/movies.json’)
.then(function(response) {
return response.json()
})
.then(function(myJson) {
console.log(myJson)
})
postData(‘http://example.com/answer’, { answer: 42})
.then(data => console.log(data)) // JSON from `response.json()` call
.catch(error => console.error(error))
function postData(url, data) {
// Default options are marked with *
return fetch(url, {
body: JSON.stringify(data), // must match ‘Content-Type’ header
cache: ‘no-cache’, // *default, no-cache, reload, force-cache, only-if-cached
credentials: ‘same-origin’, // include, same-origin, *omit
headers: {
‘user-agent’: ‘Mozilla/4.0 MDN Example’,
‘content-type’: ‘application/json’
},
method: ‘POST’, // *GET, POST, PUT, DELETE, etc.
mode: ‘cors’, // no-cors, cors, *same-origin
redirect: ‘follow’, // manual, *follow, error
referrer: ‘no-referrer’ // *client, no-referrer
}).then(response => response.json()) // parses response to JSON
}
参考
AJAX
Promise
async await 语法描述
Fetch 语法描述