异步与promise

101 阅读4分钟

异步概念

不能直接拿到结果,需要轮询或者回调才能拿到结果的就是异步。同步任务必须直接拿到结果才能去下一步,异步任务不需要。

异步任务需要在得到结果的时候通知JS来拿结果,这里就可以用到回调函数,但是回调函数不一定只出现在异步任务里。

回调可以用到同步任务里,如array.forEach( n => console.log(n) ) 就是同步回调

辨别异步函数

如果一个函数的返回值处于

  • setTimeout
  • AJAX(即 XMLHttpRequest)
  • AddEventListener

这三个东西内部,那么这个函数就是异步函数,其他的另说

不要把AJAX 设置为同步,这样做会使请求期间页面完全卡住。

具体理解

function 摇骰子(fn){
  setTimeout(()=>{ // 箭头函数
    fn(parseInt(Math.random() * 6) + 1)
  },1000)
}

可以简化为箭头函数,由于 f1 声明之后只用了一次,所以可以删掉 f1

function f1(x){ console.log(x) }
摇骰子(f1)

改为

摇骰子(x => {
  console.log(x) 
})

再简化为

摇骰子(console.log) // 如果参数个数不一致就不能这样简化

如果参数个数不一致就不能这样简化

以 AJAX 的封装为例,来解释 Promise 的用法

ajax = (method, url, options)=>{
  const {success, fail} = options // 析构赋值
  const request = new XMLHttpRequest()
  request.open(method, url)
  request.onreadystatechange = ()=>{
    if(request.readyState === 4){
      // 成功就调用 success,失败就调用 fail
      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){}, fail: (request, status)=>{} 
}) // 左边是 function 缩写,右边是箭头函数

const {success, fail} = options // 析构赋值可以等价于

const success = option.success
const fail = option.fail

改成 Promise 写法

// 先改一下调用的姿势
ajax('get', '/xxx', { 
  success(response){}, fail: (request, status)=>{} 
})
// 上面用到了两个回调,还使用了 success 和 fail

// 改成 Promise 写法
ajax('get', '/xxx')
  .then((response)=>{}, (request)=>{})

// then 的第一个参数就是 success
// then 的第二个参数就是 fail

改造 ajax 的源码得到这个ajax()返回的含有 .then() 的对象

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){
        // 成功就调用 resolve,失败就调用 reject
        if(request.status < 400){
          resolve.call(null, request.response)
        }else if(request.status >= 400){
          reject.call(null, request)
        }
      }
    }
    request.send()
  })
}

背下这五个单词即可 return new Promise((resolve, reject)=>{})

总结

  • 第一步 return new Promise((resolve,reject)=>{...})
  • 任务成功则调用 resolve(result),任务失败则调用 reject(error)
  • resolve 和 reject 会再去调用成功和失败函数
  • 第二步,使用 .then(success, fail) 传入成功和失败函数

问题

关于异步

  1.  如果 JS 不能直接拿到一个函数的结果,可以先去执行别的代码,等结果到了再取结果,这就是异步
  2.  异步的结果可以通过轮询获取,轮询就是定时去询问结果拿到了没有
  3.  异步的结果可以通过回调获取,一般来说结果会被作为回调的第一个参数
  4.  异步的好处是可以把用来等待的时间拿去做别的事情

关于回调

  • 回调可以用于同步任务,不一定非要用于异步任务
  • 有的时候回调还可以传给一个对象,如 request.onreadystatechange,等待浏览器来调用
  • 满足某些条件的函数才被称为回调,比如我写一个函数 A,传给另一个函数 B 调用,那么函数 A 就是回调

关于promise

  1.  Promise 不是前端发明的
  2. Promise 是1976 年的一种设计模式,是前端解决异步问题的统一方案
  3.  window.Promise 是一个全局函数,可以用来构造 Promise 对象
  4.  使用 return new Promise((resolve, reject)=> {}) 就可以构造一个 Promise 对象
  5.  构造出来的 Promise 对象含有一个 .then() 函数属性

关于 return new Promise((resolve, reject)=>{...}) 中的 resolve 和 reject

  1. resolve 和 reject 并不是 .then(succes, fail) 里面的 success 和 fail,resolve 会去调用 success,reject 会去调用 fail
  2.  resolve 和 reject 可以改成任何其他名字,不影响使用,但一般就叫这两个名字
  3.  任务成功的时候调用 resolve,失败的时候调用 reject
  4.  resolve 和 reject 都只接受一个参数

关于 axios

  1.  这是一个专门用于操作 AJAX 的库
  2.  axios.get('/xxx') 返回一个 Promise 对象
  3.  axios.get('/xxx').then(s, f) 在请求成功的时候调用 s,失败的使用调用 f

现在的专业前端都在用 axios,具体可见juejin.cn/post/684490…