异步与promise
同步
如果能直接拿到结果,那就是同步
例如去医院挂号,不拿到号码你不会离开,也就是说,执行同步任务时,我们必须等到当前任务结束才能继续执行下面的任务。
异步
如果不能直接拿到结果,那就是异步。
同样是去医院,当你取到号之后可能一时半会还轮不到你,这时候你就可以先去做点其他的事,也就是说在看病之前你可以先去做其他任务,你可以每十分钟问一下(轮询)或者等到叫到你的号再过去(回调)。
以AJAX为例,request.send()之后我们并不能得到response,而是在我们的页面下载完成之后(也就是readyState = 4之后),浏览器回头调用onreadystatechange函数我们才能得到request.response。
callback(回调)
写给自己用的函数不是回调
写给别人用的函数是回调
判断同步异步
如果一个函数的返回值处于
- setTimeout
- AJAX
- AddEventListener
这三个东西的内部,那么这个函数即使异步的。
这里我们举一个摇骰子的例子:
function yao(){
setTimeout(()=>{
return parseInt(Math.random() * 6)+1
},1000)
}
分析一下:
- yao()没有return
- 箭头函数里面有return,这里返回的才是真正的结果
- 这里的箭头函数现在并没有被立即执行,所以这是一个异步任务/函数。
那么问题来了,这里的yao()因为没有return,所以yao()返回的是一个undefine值,那么我们要怎么样才能获取到异步结果呢?
答案是我们可以利用回调,写一个函数,然后把这个函数地址给它,
比如这样:
function yao(fn){
setTimeout(()=>{
fn(parseInt(Math.random()*6)+1))
},1000)
}
yao(console.log)
//function f1(x){console.log(x)}; yao(f1)的缩写
总结:
- 异步任务不能拿到结果
- 于是我们传一个回调给异步任务
- 异步任务在最后调用回调
- 调用时把结果作为回调的第一个参数
promise
在AJAX中,我们回遇到成功和失败的两个异步任务结果,那么这时候我们又应该怎么办呢?
两个方法
- 方法一,回调接受两个参数
- 方法二:搞两个回调
这里就展示两个方法的代码了
下面我们来说一下两个方法的不足:
- 命名不规范,名称五花八门
- 容易出现回调地狱,代码变得看不懂
- 很难进行错误处理
解决三个问题
为了解决上述的三个问题,promise出现了
以AJAX为例,我们先自己来封装一下一个ajax
ajax('get','/xxx')
.then((response)=>{},(request)=>{})
//虽然也是回调
//但是不需要记success和fail,
//.then的第一个参数就是success,第二个参数是fail
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){
succsess.call(null,request.response)
}else {
fail.call(null,request,request.status)
}
}
}
request.send()
}
ajax('get','/xxx',{
success(response){},fail:(request,status)=>{}
})
promise说这样写太傻了,要这样搞:
ajax = (method,url,options)=>{
return new Promise((resolve,reject)=>{
const {success,fail} = options
const request = new XMLHttpRequest()
request.open(method,url)
request.onreadystatechange = ()=>{
if(request.readyState ===4){
if(request.status<400){
resolve.call(null,request.response)
}else {
reject.call(null,request)
}
}
}
request.send()
})
}
ajax('get','/xxx')
.then((response)=>{},(request)=>{})
//虽然也是回调
//但是不需要记success和fail,
//.then的第一个参数就是success,第二个参数是fail
仔细对比一下就会发现promise写法与我们的代码没有多大的差别,改写成promise写法只需一下几步
小结
- return new Promise((resolve,reject)=>{.......})
- 任务成功调用resolve(result)
- 任务失败调用reject(error)
- resolve和reject会再去调用成功和失败函数
- 使用.then(success,fail)传入成功和失败函数