- JS异步编程模型
- AJAX封装
- Promise写法
- axios
-曾老湿, 江湖人称曾老大。
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
JS异步编程模型
什么是异步?什么是同步? |
---|
网上的解释经常混淆异步与回调。
代码语言:javascript复制## 如果能直接拿到结果,那就是同步
# 例如:
# 1.在医院挂号,你拿到号才会离开
# 2.QQ的在线发送文件,对方发送完,你接收完文件才能关闭QQ
## 如果不能直接拿到结果,那就是异步
# 例如:
# 1.你在餐厅门口等位,叫号,你拿到号可以去逛街
# 那么什么时候才能去吃饭呢?
# 你可以每隔几分钟回去问一次,还剩几个。(轮询)
# 你也可以扫码用微信接收通知。(回调)
# 2.QQ的离线发送文件。
以上是生活中的例子,那么我们接下来以代码为例子。
代码语言:javascript复制## 以AJAX为例
# request.send()之后,并不能直接得到respone
# 不信,可以console.log(request.respone)试试
# 必须等到readyState变为4后,浏览器回头调用request.onreadystatechange函数
# 我们才能得到request.response
# 这跟餐厅给你发微信提醒的过程类似
## 回调callback
# 你写给自己用的函数,不是回调
# 你写给别人用的函数,就是回调
# request.onreadystatechange就是我写给浏览器调用的
# 意思就是,你(浏览器)回头调用一下这个函数。
# 在中文中「回头」也有「将来」的意思,如:「我回头请你吃饭」
异步和回调的关系 |
---|
## 关联
# 异步任务需要在得到结果时通知JS来拿结果
# 怎么通知呢?
# 可以让JS写留一个函数地址(电话号码)给浏览器
# 异步任务完成时,浏览器调用该含税地址即可(拨打电话)
# 同时把 结果作为参数传给该函数(电话说,可以来吃饭了)
# 这个函数是我写给浏览器调用的,所以是回调函数
## 区别
# 异步任务需要用到回调函数来通知结果。
# 但回调函数不一定只用在异步任务里
# 回调可以用到同步任务里
# array.forEach(n=>console.log(n))就是同步回调
如何判断一个函数时异步还是同步 |
---|
如果一个函数的返回值处于下面几种情况,就是异步。
1.setTimeout 2.AJAX(即XMLHTTPRequest) 3.AddEventListener
求都嘛得~ 我听说AJAX可以设置为同步的。
傻X前端才会把AJAX设置为同步,这样做会使请求期间页面卡住。
我们试一下把之前代码改成同步,整个页面都会卡主。
代码语言:javascript复制getJSON.onclick = () =>{
const request = new XMLHttpRequest()
request.open('GET','/zls.json',false)
request.onreadystatechange = () =>{
if(request.readyState === 4 ){
if(request.status >= 200 && request.status < 300){
console.log(request.response)
const object = JSON.parse(request.response)
myName.textContent = object.name
}
}
}
request.send()
}

我点了两个请求,先请求json再请求xml,会发现,必须等到json请求返回之后,才会发起对xml的请求。
我们改回异步试试。
代码语言:javascript复制getJSON.onclick = () =>{
const request = new XMLHttpRequest()
request.open('GET','/zls.json')
request.onreadystatechange = () =>{
if(request.readyState === 4 ){
if(request.status >= 200 && request.status < 300){
console.log(request.response)
const object = JSON.parse(request.response)
myName.textContent = object.name
}
}
}
request.send()
}

两个请求可以同时触发,异步返回结果。
如果异步任务有两个结果怎么办? |
---|
当我们的异步结果有两个,一个是成功,一个是失败,我们该怎么做?
方法一:回调接受两个参数
代码语言:javascript复制fs.readFile('./1.txt',(error,data)=>{
if(error){console.log('失败');return}
console.log(data.toString())//成功
})
方法二:搞两个回调呗
代码语言:javascript复制ajax('GET','/1.json',data()=>{},error()=>{})
//前面函数是成功回调,后面函数是失败回调
ajax('GET','/1.json',{
success:()=>{},fail:()=>{}
})
//接受一个对象,对象有两个key,表示成功和失败
但是...特么的,只要有但是,那么但是之前的都是废话,上面两种方法都不行。
不管是方法一,还是方法二,都有问题。
1.不规范,名称五花八门,因为是约定,有人用success error ,有人用success fail,有人用done fail
2.容易出现回调地狱,代码变得看不懂
3.很难进行错误处理
回调地狱举例:
代码语言:javascript复制getUser(user=>{
getGroups(user,(group)=>{
groups.forEach((g)=>{
g.filter(x => x.ownerId === user.id).forEach(x => console.log(x))
})
})
})
这还只是4层回调,你能想象20层回调么?
网上吐槽回调地狱的图片【HaDoGen】

如何解决上述的三个问题呢?
1.规范回调的名字或顺序 2.拒绝回调地狱,让代码可读性更强 3.很方便的捕获错误
前端程序猿开始翻书了
- 1976年,Daniel P.Friedman 和 David Wise。
- 俩人提出了Promise思想。
- 后人基于此发明了Future、Delay、Deferred等。
- 前端结合Promise和JS,制定了Promise/A 规范。
- 该规范详细描述了Promise的原理和使用方法。
AJAX封装
代码语言:javascript复制ajax = (method,url,options)=>{
const {success,fail} = options //析构赋值
const request = new XMLHttpRequest()
request.open(method,url)
request.onreadystatechange = () =>{
if(request.readyState === 4){
//成功就调用 success,失败就用 fail
if(request.status < 400){
success.call(null,request.respone)
}else if(request.status >= 400){
fail.call(null,request,request.status)
}
}
}
request.send()
}
// 调用封装函数
ajax('get','/xxx',{
success(response){},fail:(request,status)=>{}
})
//左边是function缩写,右边是箭头函数,记下来,别再问我
Promise写法
Promise说,上面这个代码太傻了,我们使用Promise写法吧。因为之前我们说的那三个原因,不规范、回调地狱、很难错误处理。
代码语言:javascript复制// 先改一下调用姿势
ajax('get','/xxx',{
success(respone){},fail:(request,status)=>{}
})
// 上面代码,用到了两个回调,还是用了 success 和 fail
// 改成Promise写法
ajax('get','/xxx').then((respone)=>{},(request)=>{})
// 虽然也是回调
// 但是不用记success和fail了
// then的第一个参数就是success
// then的第二个参数就是fail
// 请问ajax()返回了个啥?
// 返回了一个含有.then()方法的对象呗
// 那么再请问,如何得到这和个含有.then()的对象呢?
// 那就要改造ajax的源码了,如下:
ajax = (method,url,options)=>{
return new Promise((resolve,reject)=>{
const {suuccess,fail} = options
const request = new XMLHttpRequest()
request.open(method,url)
request.onreadystatechange = () =>{
if(request.readyState === 4){
if(request.status < 400){
resolve.call(null,request.respone)
}else if(request.status >= 400){
reject.call(null,request)
}
}
}
request.send()
})
}
背下来下面五个单词即可,等你用熟了,自然就掌握了Promise。
代码语言:javascript复制return new Promise((resolve,reject)=>{}
小结:
第一步: return new Promise((resolve,reject)=>{...}) 任务成功则调用resolve(result) 任务失败则调用reject(error)
第二步: 使用.then(success,fail)传入成功和失败函数
点到为止: Promise先介绍到这里,高级用法,我们后面再说,先把五个单词背会
封装AJAX的缺点 |
---|
1.post无法上传数据 request.send(这里可以上传数据)
2.不能设置请求头 request.setRequestHeader(key,value)
怎么解决呢? 花时间把ajax写到完美(有时间可以做) 使用JQuery.ajax(这个可以) 使用axios(这个库比JQuery逼格高)
JQuery.ajax |
---|
已经非常完美,进入JQuery文档,搜索ajax找到jQuery.ajax,看看参数说明,然后直接看代码示例,看看jQuery的封装,就知道自己的封装有多么的辣鸡了。
封装的优点: 支持更多形式的参数 支持Promise 支持的功能超多
我们需要掌握jQuery.ajax嘛? 不用,现在的专业前端都在用axios 写篇博客,罗列一下功能,就可以忘掉jQuery了。

axios
jQuery.ajax我们可以忘了,目前,最新的AJAX库,axios
划重点,显然它抄袭了jQuery的封装思路。如果有人问我你记得axios的API吗?对不起,不记得,但是我写了博客...
代码示例:
代码语言:javascript复制axios.get('/5.json')
.then(respone =>
console.log(response)
)
axios高级用法 |
---|
JSON自动处理 axios如果发现响应的Content-Type是json,就会自动 调用JSON.parse,所以说,正确设置Content-Type是好习惯。
请求拦截器 你可以 在所有请求里加东西,比如加查询参数
响应拦截器 你可以在所有响应里加东西,甚至改内容
可以生成不同实例 不同的实例可以设置不同的配置,用于复杂场景。