41. 异步与Promise
Promise
什么是异步?什么是同步?
网上的解释经常混淆异步与回调
什么是同步?
如果能直接拿到结果就是同步。
举例:
比如你在医院挂号,你拿到号才会离开窗口。
同步任务可能消耗10毫秒,也可以需要3秒,总之不拿到结果你是不会离开的。
什么是异步?
如果不能直接拿到结果就是异步。
举例:
比如你在餐厅门口等位,你拿到号可以去逛街。
什么时候才能真正吃饭呢?
你可以每10分钟去餐厅问一下(轮询)。
你也可以扫码用微信接受通知。
异步举例
以AJAX为例
request.send()
之后,并不能直接得到response,不信的话可以用console.log(request.response)
试试。必须等到readyState变为4后,浏览器回头调用request.onReadystatechange
函数,我们才能得到request.response,这跟餐厅给你发送微信提醒的过程是类似的。
回调callback
你写给自己用的函数,不是回调,你写给别人用的函数,就是回调。request.onreadystatechange
就是我写给浏览器调用的意思就是你(浏览器)回头调一下这个函数。回头也有将来的意思,就是在将来的某一个时刻,调用下这个函数。
回调
什么是回调?
写了却不调用,给别人调用的函数,就是回调。(回头你调用一下呗)
回调举例1
把函数1给另一个函数2
分析
我调用f1没有?答:没有
我把f1传给f2(别人)了没有?答:传了
f2调用f1了没有?f2调用了f1
那么,f1是不是我写给f2调用的函数,答:是
所以,f1是回调。
回调举例2
f1是回调函数,被传给f2,f1作为回调函数接受'你好'作为参数。
异步与回调的关系
关联
异步任务需要在得到结果时通知JS来拿结果,可以让JS写留一个函数地址(电话号码)给浏览器。异步任务完成时浏览器调用该函数地址即可(拨打电话)。同时把结果作为参数传给该函数(电话里说可以来吃了)。这个函数时我写给浏览器调用的,所以是回调函数。
区别
异步常常用到回调,但是不一定要用到回调。
异步任务需要用到回调函数来通知结果(也可以用到轮询)
调函数不一定只用在异步任务里
回调可以用到同步任务里,比如,array.forEach(n => console.log(n))就是同步回调。
如何判断一个函数是同步还是异步
很简单,跟据特征或者文档。
判断同步异步
如果一个函数的返回值处于下面三种情况,那么这个函数就是异步函数。
setTimeout
AJAX(即XMLHttpRequest)
AddEventListener
问:我听说AJAX可以设置为同步的
答:啥x前端才把AJAX设置为同步的,这样做会使请求期间页面卡住。
AJAX也可以做同步请求,只需要添加false即可。
request.open("get", "/5.json", false)
看下面图中绿色的bar,当把AJAX设置成同步之后,会等上一个请求完成才开始执行,同时页面也会出现卡顿。浏览器知道用户点击了,但是不会有任何反馈。
举例(什么样的代码是异步的?)
摇骰子
分析
摇骰子()没有写return,那就是return undefined
箭头函数里有return,返回真正的结果,所以这是一个异步函数/异步任务。
如何拿到异步结果?
答:可以用回调。写个函数,然后把函数地址给它。然后,要求摇骰子函数得到结果后把结果作为参数传给f1。
简化为箭头函数
由于f1声明之后只用了一次,所以可以删掉f1
著名的面试题
⚠️注意:
总结
异步任务不能拿到结果
于是我们传一个回调给异步任务
异步任务完成时调用回调
调用的时候把结果作为参数
希望你已经理解上面的过程。
如果异步任务有两个结果成功或失败,怎么办
两个结果
方法一:回调接受两个参数
方法二:搞两个回调
这些方法的不足
不管方法一还是方法二,都有问题
面试官会问,为什么要用到promise?以下就是答案
不规范,名称五花八门,有人用success + error, 有人用success + fail, 有人用done + fail
容易出现回调地狱,代码变得看不懂
很难进行错误处理
回调地狱举例
这还只是四层回调,你能想象20层回调吗?
怎么解决回调问题
有什么办法能解决这三个问题
规范回调的名字或顺序
拒绝回调地狱,让代码可读性更强
很方便地捕获错误
前端程序员开始翻书了
1976年,Daniel P. Friedman和David Wise两人提出了Promise思想。后人基于此发明了Future,Delay,Deferred等。
前端结合Promise和JS,制定了Promise/A+规范。该规范详细描述了Promise的原理和使用方法。
以AJAX的封装为例来解释Promise的用法
Promise说这代码太傻了,我们改成Promise写法
完整代码
return new Promise((resolve, reject) =>{})
背下这五个单词即可,等你用熟了。。。
小结
第一步
return new Promise ((resolve,reject)=>{...})
任务成功则调用 resolve(result)
任务失败则调用 reject(error)
resolve 和reject 会再去调用成功和失败函数
第二步
使用
.then(success, fail)
传入成功和失败函数点到为止
先讲到这里,Promise 还有高级用法,以后说
我们封装的 ajax 的缺点
post 无法上传数据
request.send(这里可以上传数据)
不能设置请求头
request.setRequestHeader(key, value)
怎么解决呢?
花时间把 ajax 写到完美(有时间可以做)
使用 jQuery.ajax(这个可以)
使用 axios(这个库比 jQuery逼格高)
jQuery.ajax
已经非常完美
进入jQuery 的文档,搜索 ajax,找到jQuery.ajax
看看参数说明,然后直接看代码示例
看看jQuery 的封装,就知道自己的封装是辣鸡了
封装优点
支持更多形式的参数
支持 Promise
支持的功能超多
我们需要掌握 jQuery.ajax 吗?
不用,现在的专业前端都在用 axios
写篇博客罗列一下功能,就可以忘掉jQuery了
axios
目前最新的 AJAX库
显然它抄袭了 jQuery 的封装思路
方方记得 axios 的API 吗?
通过这个博客我们可以快速了解 axios 的用法
推荐大家也可以通过写博客来学习一个库
代码示例
axios 高级用法
JSON 自动处理
axios 如何发现响应的 Content-Type 是json
就会自动调用 JSON.parse
所以说正确设置 Content-Type 是好习惯
请求拦截器
你可以在所有请求里加些东西,比如加查询参数.
响应拦截器
你可以在所有响应里加些东西,甚至改内容
比如说发一个请求,但是后端的api还没有写好,就可以通过响应拦截器来篡改
可以生成不同实例(对象)
不同的实例可以设置不同的配置,用于复杂场景
封装!封装!封装! 初级程序员学习 API(包括 vue / React 的 API) 中级程序员学习如何封装 高级程序员造轮子
课后作业
Promise问答题
你需要自行查看Promise的MDN文档才能答对
Axios问答题
你需要自行查看axios的文档才能答对
我们的项目会经常用到这俩玩意
所以忘了也没关系
总结
Promise的最大缺点就是不可以取消,所以axios发明了axios.CancelToken
,本质就是编个号。
异步是什么?
不能直接拿到结果的就叫异步
异步为什么会用到回调?
需要用回调拿到不能直接拿到的结果
回调有哪三个问题?
回调地狱,名字不规范,错误处理
Promise是什么?
1976年的一种设计模式
如何使用Promise?背下来五个词
return new Promise((resolve,reject)=>{})
最后更新于
这有帮助吗?