异步
如果能直接拿到结果
- 那就是同步
- 医院挂号,你需要拿到号才会离开窗口
- 没有拿到号,你不会离开
如果不能直接拿到结果
- 异步
- 定制餐具,可以在别人制作餐具的同时,去做其他事情
- 不需要停下来等待
异步列子
AJAX
- request.send()之后,并不能直接得到response
- 必须等到readyState变为4后,浏览器回头调用request.onreadystatechange函数
- 才能够获取request.response
回调callback
function f1(){}
function f2(fn){
fn()
}
f2(f1)
f1是回调函数
异步和回调的关系
关联
- 异步任务需要在得到结果时通知js来拿到结果
- 可以让js写一个函数地址
- 异步任务完成时浏览器调用该函数地址即可
- 同时把结果作为参数传递给该函数
- 这个函数是写给浏览器调用的,所以是回调函数
区别
- 异步任务需要用到回调函数来通知结果
- 但回调函数不一定只用在异步任务里面
- 回调函数也可以用于同步任务
判读是否同步
- setTimeout
- AJAX
- AddEventListener
fn = function(value){
console.log(value)
}
function f1(fn){
setTimeout(
() => {
fn(Math.ceil(Math.random()*6))
},
1000
)
}
f1(fn)
简化
fn = console.log
function f1(fn){
setTimeout(
() => {
fn(Math.ceil(Math.random()*6))
},
1000
)
}
f1(fn)
两个结果
ajax('get', '1.json', data=>{}, error=>{});
ajax('get', '1.json',
{
success:()=>{},
fail: () =>{}
}
)
不足
问题
- 不规范,名称不统一
- 容易出现
回调地狱
- 很难处理错误
回调地狱
getUser(
user=>{
getInfor(
user, (groups) => {
//...
}
)
}
)
解决回调问题
- 规范回调的名字或顺序
- 拒绝回调地狱,让代码可读性更强
- 方便地捕获错误
ajax = (method, url, options) => {
const {success, fail} = options;
const request = new XMLHttpRequest()
request.open(method, url);
request.onreadystatechange = () => {
if(request.readyState === 4){
if(request.status < 400) {
success.call(null, request.response)
} else if(request.status >= 400){
fail.call(null, request, request.status)
}
}
}
request.send()
}
ajax(
'get', '/xxx',
{
success(response){console.log(1)},
fail: (request, status) => {console.log(2)}
}
)
修改为promise
ajax = (method, url) => {
return new Promise(
(resolve, reject) => {
const request = new XMLHttpRequest()
request.open(method, url);
request.onreadystatechange = () => {
if(request.readyState === 4){
if(request.status < 400) {
resolve.call(null, request.response)
} else if(request.status >= 400){
reject.call(null, request)
}
}
}
request.send()
}
)
}
ajax('get', '/xxx').then(
(response) => {console.log(1)}, (request) => {console.log(2)}
)
小结
第一步
- return new Promise((resolve, reject) => {})
- 任务成功调用resolve(result)
- 任务失败调用reject(error)
- resolve 和 reject会再去调用成功和失败函数
第二步
- 使用.then(success, fail)传入成功和失败函数