异步和Promise

192 阅读6分钟

异步与回调的区别

同步

  • 如果能直接拿到结果

  • 那就是同步

  • 比如你在医院挂号,你拿到号才会离开窗口

  • 同步任务可能消耗 10 毫秒,也可能需要 3 秒

  • 总之不拿到结果你是不会离开的

异步

  • 如果不能直接拿到结果

  • 那就是异步

  • 比如你在餐厅门口等位,你拿到号可以去逛街

  • 什么时候才能真正吃饭呢?

  • 你可以每10分钟去餐厅问一下(轮询

  • 你也可以扫码用微信接收通知(回调

异步举例

  • 以AJAX为例:request.send() 之后,并不能直接得到 response,必须等到 readyState 变为 4 后,浏览器回头调用 request.onreadystatechange 函数,我们才能得到 request.response,这跟餐厅给你发送微信提醒的过程是类似的。

回调 callback

  • 你写给自己用的函数,不是回调

  • 你写给别人用的函数,就是回调

  • request.onreadystatechange 就是我写给浏览器调用的

  • 意思就是你(浏览器)回头调一下这个函数,在中文里,「回头」也有「将来」的意思,如「我回头请你吃饭」。

  • 写了却不调用,给别人调用的函数,就是回调

异步和回调的关系

关联

  • 异步任务需要在得到结果时通知 JS 来拿结果

  • 怎么通知呢?

  • 可以让 JS 留一个函数地址(电话号码)给浏览器

  • 异步任务完成时浏览器调用该函数地址即可(拨打电话)

  • 同时把结果作为参数传给该函数(电话里说可以来吃了)

  • 这个函数是写给浏览器调用的,所以是回调函数

区别

  • 异步任务需要用到回调函数来通知结果

  • 但回调函数不一定只用在异步任务里

  • 回调可以用到同步任务里

  • array.forEach( n => console.log(n) ) 就是同步回调

小试牛刀

  • 关于异步,正确的有
  1. 如果 JS 不能直接拿到一个函数的结果,可以先去执行别的代码,等结果到了再取结果,这就是异步

  2. 异步的结果可以通过轮询获取,轮询就是定时去询问结果拿到了没有

  3. 异步的结果可以通过回调获取,一般来说结果会被作为回调的第一个参数

  4. 异步的好处是可以把用来等待的时间拿去做别的事情

  • 关于回调,正确的有
  1. 满足某些条件的函数才被称为回调,比如我写一个函数 A,传给另一个函数 B 调用,那么函数 A 就是回调

  2. 回调可以用于同步任务,不一定非要用于异步任务(只需要加一个false)

image.png

  1. 有的时候回调还可以传给一个对象,如 request.onreadystatechange,等待浏览器来调用

判断同步异步

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

  • setTimeout

  • AJAX(即 XMLHttpRequest)

  • AddEventListener

  • 这三个东西内部,那么这个函数就是异步函数

2.png

3.png

4.png

5.png

6.png

7.png

总结

  • 异步任务不能拿到结果

  • 于是我们传一个回调给异步任务

  • 异步任务完成时调用回调

  • 调用的时候把结果作为参数

如果异步任务有两个结果成功或失败,怎么办?

8.png

这些方法的不足(重点记忆3个问题)

  • 不管方法一还是方法二,都有问题
  1. 不规范,名称五花八门,有人用 success + error,有人用 success + fail,有人用 done + fail

  2. 容易出现回调地狱,代码变得看不懂

  3. 很难进行错误处理

  • 回调地狱举例
getUser( user => {
  getGroups(user, (groups)=>{
    groups.forEach( (g)=>{
      g.filter(x => x.ownerId === user.id)
       .forEach(x => console.log(x))
    })
  })
})

怎么解决回调问题

有什么办法能解决这三个问题

  • 规范回调的名字或顺序

  • 拒绝回调地狱,让代码可读性更强

  • 很方便地捕获错误

前端程序员开始翻书了

  • 1976 年,Daniel P. Friedman 和 David Wise

  • 俩人提出 Promise 思想

  • 后人基于此发明了 Future、Delay、Deferred 等

  • 前端结合 Promise 和 JS,制订了 Promise/A+ 规范

  • 该规范详细描述了 Promise 的原理和使用方法

Promise

  • Promise对象表示异步操作的最终完成(或失败)及其结果值。

  • 从本质上讲,promise 是一个返回的对象,您将回调附加到该对象,而不是将回调传递给函数。

9.png

用Promise改写一下代码

10.png

11.png

  • 注意:Promise.reject() 方法返回一个 Promise因给定原因而被拒绝的对象。Promise.resolve() 方法返回一个 Promise使用给定值解析的对象。

  • 重点记忆:return new Promise((resolve, reject)=>{})

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

  1. resolve 和 reject 可以改成任何其他名字,不影响使用,但一般就叫这两个名字

  2. 任务成功的时候调用 resolve,失败的时候调用 reject

  3. resolve 和 reject 都只接受一个参数

  4. resolve 和 reject 并不是 .then(succes, fail) 里面的 success 和 fail,resolve 会去调用 success,reject 会去调用 fail

小结

第一步

  • return new Promise((resolve,reject)=>{...})

  • 任务成功则调用 resolve(result)

  • 任务失败则调用 reject(error)

  • resolvereject 会再去调用成功和失败函数

第二步

  • 使用 .then(success, fail) 传入成功和失败函数

  • 该**then()** 方法返回一个Promise ., 它最多需要两个参数:. 的成功和失败情况的回调函数 Promise

小试牛刀

  • 关于 Promise,正确的有
  1. Promise 不是前端发明的

  2. Promise 是目前前端解决异步问题的统一方案

  3. window.Promise 是一个全局函数,可以用来构造 Promise 对象

  4. 使用 return new Promise((resolve, reject)=> {}) 就可以构造一个 Promise 对象

  5. 构造出来的 Promise 对象含有一个 .then() 函数属性

封装的 ajax 的缺点

post 无法上传数据

  • request.send(这里可以上传数据)

不能设置请求头

  • request.setRequestHeader(key, value)

怎么解决呢?

  • 花时间把 ajax 写到完美(有时间可以做)

  • 使用 jQuery.ajax(这个可以)

  • 使用 axios(这个库比 jQuery 逼格高)

jQuery.ajax

封装优点

  • 支持更多形式的参数

  • 支持 Promise

  • 支持的功能超多

axios

目前最新的 AJAX 库

  • 它抄袭了 jQuery 的封装思路

代码示例

axios.get('/5.json')
  .then( response =>
    console.log(response)
  )
  • 关于 axios,正确的有
  1. 这是一个专门用于操作 AJAX 的库

  2. axios.get('/xxx') 返回一个 Promise 对象

  3. axios.get('/xxx').then(s, f) 在请求成功的时候调用 s,失败的使用调用 f

axios 高级用法

JSON 自动处理

  • axios 如何发现响应的 Content-Type 是 json

  • 就会自动调用 JSON.parse

  • 所以说正确设置 Content-Type 是好习惯

请求拦截器

  • 你可以在所有请求里加些东西,比如加查询参数

响应拦截器

  • 你可以在所有响应里加些东西,甚至改内容

  • 可以生成不同实例(对象)

  • 不同的实例可以设置不同的配置,用于复杂场景

总结

  • 异步是什么

  • 异步为什么会用到回调

  • 回调哪三个问题:地域、名字、错误处理

  • Promise 是什么:1976 年的一种设计模式

  • 如何使用 Promise:背下来五个词

  • 如何使用 Axios:发个请求试用看看

  • Promise 是前端解决异步问题的统一方案