异步与promise

131 阅读3分钟

异步与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中,我们回遇到成功和失败的两个异步任务结果,那么这时候我们又应该怎么办呢?

两个方法

  1. 方法一,回调接受两个参数
  2. 方法二:搞两个回调

这里就展示两个方法的代码了

下面我们来说一下两个方法的不足:

  1. 命名不规范,名称五花八门
  2. 容易出现回调地狱,代码变得看不懂
  3. 很难进行错误处理

解决三个问题

为了解决上述的三个问题,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写法只需一下几步

小结
  1. return new Promise((resolve,reject)=>{.......})
  2. 任务成功调用resolve(result)
  3. 任务失败调用reject(error)
  4. resolve和reject会再去调用成功和失败函数
  5. 使用.then(success,fail)传入成功和失败函数