异步与Promise(面试必考)
AJAX(Async JavaScript And XML)
内容:Ajax异步编程在js里的统一解决方案(js异步编程模型) Promise
什么是异步?什么是同步?
同步:能直接拿到结果
比如你在医院挂号,拿到号才会离开窗口。
同步任务可能消耗10ms,也可能需要3s
总之不拿到结果你是不会离开的
异步:不能直接拿到结果
比如你在餐厅门口等位,拿到号可以去逛街
什么时候才能真正吃饭呢?
你可以每10min去餐厅问一下(轮询)
你也可以扫码用微信接收通知(回调)
异步通常指"异步加回调"
举例
1.以ajax为例
request.send()之后,并不能直接得到response
不信console.log(request.response)试试
必须等到readState变为4后,浏览器回头调用
request.onreadystatechange函数
我们才能得到request.response
这跟餐厅给你发送微信提醒的过程是类似的
补充:在js中发一个网络请求并得到响应大概要几百ms~1/2s
getJSON.onclick = () => {
...
request.send()
console.log(request.response) //不能直接得到response
setTimeout(() => { //2s后得到response
console.log(request.response)
}, 2000)
}
下载完成后浏览器会回调request.onreadystatechange函数
所以上面的代码等价于
request.onreadystatechange = () => {
if (request.readyState === 4 && request.status == 200) {
console.log(request.response)
...
}
打印出response后就是3s后
2.回调callback
你写给自己用的函数,不是回调
你写给别人用的函数,就是回调
request.onreadystatechange就是我写给浏览器调用的
意思就是浏览器回头调一下这个函数
「回头」也有「将来」的意思,如「我回头请你吃饭」
举例
1.把函数1给另一个函数2
function f1(){}
function f2(fn){
fn()
}
f2(f1)
我调用f1没有?没有
我把f1传给f2了没有?传了
f2调用f1了没有?调了
那么f1是不是我写给f2调用的函数?是,所以f1是回调
没有调用、传给别人了、别人调用了
补充
//request.setCallback(onreadystatechange)
request.onreadystatechange
是不是参数这个问题并不大,直接写一样的效果
不过一般不推荐放到对象上,最好作为参数传给它,防止别人不知道
抬杠1,如果我传给f2的参数不是函数呢?
会报错:fn不是一个函数。看到报错你不就知错了
抬杠2
function f1(x){
console,log(x)
}
function f2(fn){
fn('你好')
}
f2(f1)
f1怎么会有一个x参数
fn(‘你好’)中的fn就是f1对吧
fn(‘你好’)中的’你好’会被赋值给参数x对吧
所以x就是’你好’。x表示第1个参数而已
异步和回调的关系
回调就是我把一个函数传给你 或者传到全局函数request上
关联
异步任务需要在得到结果时通知js来拿结果
怎么通知呢?
可以让js留一个函数地址(电话号码)给浏览器
异步任务完成时浏览器调用该函数地址即可(拨打电话)
同时把结果作为参数传给该函数(电话里说可以来吃了)
这个函数是我写给浏览器调用的,所以是回调函数
区别
异步任务常常用到回调函数来通知结果,但不一定非要用回调。也可以用轮循
回调函数也不一定只用在异步任务里,也可以用到同步任务里
array.forEach(n=>console.log(n))
就是同步回调
array里有多少个元素forEach就会调用函数n多少次
判断同步异步
怎么区分一个函数是同步还是异步?
根据特征或文档
如果一个函数的返回值处于这3个东西内部,那么这个函数就是异步函数
setTimeout
Ajax(即XMLHttpRequest)
AddEventListener
等下,我听说Ajax可以设置为同步的
傻X前端才把Ajax设置为同步的,这样会使请求期间页面卡住。
例子:异步1个结果的处理
1s后返回1~6的随机数
function 摇骰子(){
setTimeout(()=>{
return parseInt(Math.random() * 6 ) + 1
},1000)
//return undefined
}
const n=摇骰子()
console.log(n) //undefined
摇骰子()没有写return,那就是return undefined
箭头函数里有return,返回真正的结果
注意这2个return属于不同的函数
所以这是一个异步函数/任务
那怎么才能拿到异步结果(1~6的随机数)?
可以用回调。写个函数,然后把函数地址给它
function f1(x){console.log(x)}
摇骰子(f1)
然后我要求摇骰子函数得到结果后把结果作为参数传给f1
function 摇骰子(fn){
setTimeout(()=>{
fn(parseInt(Math.random() * 6 ) + 1) //得到结果后传给fn
},1000)
}
将结果传给fn,这时候就能输出结果了。
简化为箭头函数。f1声明后只用了一次,所以可以删掉f1
优化技巧: 函数声明后只用了一次时,可以简化为匿名函数
function f1(x){
console.log(x