promise是什么?

理解

抽象表达:

  1. Promise是一门新技术
  2. Promise是JS异步编程的新方案 (之前采用回调函数就会造成回调地狱)

    具体表达:

  3. 从语法来说:Promise 是一个构造函数

  4. 从功能上来说:Promise 对象用来封装一个异步操作并可以获取其成功/ 失败的结果值

Promise 基本原理

  1. Promise 是一个类,在执行这个类的时候会传入一个执行器,这个执行器会立即执行
  2. Promise 会有三种状态
    • Pending 等待
    • Fulfilled 完成
    • Rejected 失败
  3. 状态只能由 Pending —> Fulfilled 或者 Pending —> Rejected,且一但发生改变便不可二次修改;
  4. Promise 中使用 resolve 和 reject 两个函数来更改状态;
  5. then 方法内部做但事情就是状态判断
    • 如果状态是成功,调用成功回调函数
    • 如果状态是失败,调用失败回调函数

1.png

Promise 使用情况

promise是用来解决两个问题的:

  • 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
  • promise可以支持多个并发的请求,获取并发请求中的数据
  • 这个promise可以解决异步的问题,本身不能说promise是异步的

使用Promise基本api

  1. Promise构造函数: Promise (excutor) {}
    excutor函数: 同步执行 (resolve, reject) => {}
    resolve函数: 内部定义成功时我们调用的函数 value => {}
    reject函数: 内部定义失败时我们调用的函数 reason => {}
    说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
  2. Promise.prototype.then方法: (onResolved, onRejected) => {}
    onResolved函数: 成功的回调函数 (value) => {}
    onRejected函数: 失败的回调函数 (reason) => {}
    说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
    返回一个新的promise对象
  3. Promise.prototype.catch方法: (onRejected) => {}
    onRejected函数: 失败的回调函数 (reason) => {}
    说明: then()的语法糖, 相当于: then(undefined, onRejected)
  4. Promise.resolve方法: (value) => {}
    value: 成功的数据或promise对象
    说明: 返回一个成功/失败的promise对象
  5. Promise.reject方法: (reason) => {}
    reason: 失败的原因
    说明: 返回一个失败的promise对象
  6. Promise.all方法: (promises) => {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
  7. Promise.race方法: (promises) => {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态

手写关键问题

1.如何改变promise的状态?

(1)resolve(value): 如果当前是pendding就会变为resolved
(2)reject(reason): 如果当前是pendding就会变为rejected
(3)抛出异常: 如果当前是pendding就会变为rejected

2.一个promise指定多个成功/失败回调函数, 都会调用吗?

当promise改变为对应状态时都会调用

  1. const p = new Promise((resolve, reject) => {
  2. // resolve(1) // promise变为resolved成功状态
  3. // reject(2) // promise变为rejected失败状态
  4. // throw new Error('出错了') // 抛出异常, promse变为rejected失败状态, reason为 抛出的error
  5. throw 3 // 抛出异常, promse变为rejected失败状态, reason为 抛出的3
  6. })
  7. p.then(
  8. value => {},
  9. reason => {console.log('reason', reason)}
  10. )
  11. p.then(
  12. value => {},
  13. reason => {console.log('reason2', reason)}
  14. )

3.改变promise状态和指定回调函数谁先谁后?

  • 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  • 如何先改状态再指定回调?
    ① 在执行器中直接调用resolve()/reject()
    ② 延迟更长时间才调用then()
  • 什么时候才能得到数据?
    ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
  1. // 常规: 先指定回调函数, 后改变的状态
  2. new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. resolve(1) // 后改变的状态(同时指定数据), 异步执行回调函数
  5. }, 1000);
  6. }).then(// 先指定回调函数, 保存当前指定的回调函数
  7. value => {console.log('value', value)},
  8. reason => {console.log('reason', reason)}
  9. )
  10. // 如何先改状态, 后指定回调函数
  11. new Promise((resolve, reject) => {
  12. resolve(1) // 先改变的状态(同时指定数据)
  13. }).then(// 后指定回调函数, 异步执行回调函数
  14. value => {console.log('value2', value)},
  15. reason => {console.log('reason2', reason)}
  16. )
  17. console.log('-------')
  18. const p = new Promise((resolve, reject) => {
  19. setTimeout(() => {
  20. resolve(1) // 后改变的状态(同时指定数据), 异步执行回调函数
  21. }, 1000);
  22. })
  23. setTimeout(() => {
  24. p.then(
  25. value => {console.log('value3', value)},
  26. reason => {console.log('reason3', reason)}
  27. )
  28. }, 1100);

4. promise.then()返回的新promise的结果状态由什么决定?

  • 简单表达: 由then()指定的回调函数执行的结果决定
  • 详细表达:
    ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
    ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
    ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
  1. new Promise((resolve, reject) => {
  2. // resolve(1)
  3. reject(1)
  4. }).then(
  5. value => {
  6. console.log('onResolved1()', value)
  7. // return 2
  8. // return Promise.resolve(3)
  9. // return Promise.reject(4)
  10. throw 5
  11. },
  12. reason => {
  13. console.log('onRejected1()', reason) //1
  14. // return 2
  15. // return Promise.resolve(3)
  16. // return Promise.reject(4)
  17. throw 5
  18. }
  19. ).then(
  20. value => {
  21. console.log('onResolved2()', value)
  22. },
  23. reason => {
  24. console.log('onRejected2()', reason) //5
  25. }
  26. )

5.then 链式操作的用法?

  • promise的then()返回一个新的promise, 可以开成then()的链式调用
  • 通过then的链式调用串连多个同步/异步任务
  • 所以,从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的:
  1. new Promise((resolve, reject) => {
  2. setTimeout(() => {
  3. console.log("执行任务1(异步)")
  4. resolve(1)
  5. }, 1000);
  6. }).then(
  7. value => {
  8. console.log('任务1的结果: ', value)
  9. console.log('执行任务2(同步)')
  10. return 2
  11. }
  12. ).then(
  13. value => {
  14. console.log('任务2的结果:', value)
  15. return new Promise((resolve, reject) => {
  16. // 启动任务3(异步)
  17. setTimeout(() => {
  18. console.log('执行任务3(异步)')
  19. resolve(3)
  20. }, 1000);
  21. })
  22. }
  23. ).then(
  24. value => {
  25. console.log('任务3的结果: ', value)
  26. }
  27. )
  28. /* 输出为
  29. 执行任务1(异步)
  30. 任务1的结果: 1
  31. 执行任务2(同步)
  32. 任务2的结果: 2
  33. 执行任务3(异步))
  34. 任务3的结果: 3
  35. */

6.promise异常传/穿透?

  • 当使用promise的then链式调用时, 可以在最后指定失败的回调,
  • 前面任何操作出了异常, 都会传到最后失败的回调中处理

7.中断promise链?

  • 当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
  • 办法: 在回调函数中返回一个pendding状态的promise对象
  1. new Promise((resolve, reject) => {
  2. // resolve(1)
  3. reject(1)
  4. }).then(
  5. value => {
  6. console.log('onResolved1()', value)
  7. return 2
  8. },
  9. // reason => {throw reason}
  10. ).then(
  11. value => {
  12. console.log('onResolved2()', value)
  13. return 3
  14. },
  15. reason => {throw reason}
  16. ).then(
  17. value => {
  18. console.log('onResolved3()', value)
  19. },
  20. reason => Promise.reject(reason)
  21. ).catch(reason => {
  22. console.log('onReejected1()', reason) //当前代码输出为 onReejected1() 1
  23. // throw reason
  24. // return Promise.reject(reason)
  25. return new Promise(() => {}) // 返回一个pending的promise 中断promise链
  26. }).then(
  27. value => {
  28. console.log('onResolved3()', value)
  29. },
  30. reason => {
  31. console.log('onReejected2()', reason)
  32. }
  33. )
  34. /*
  35. 如果promise为resolve(1) 输出为
  36. onResolved1() 1
  37. onResolved2() 2
  38. onResolved3() 3
  39. onResolved3() undefined
  40. */
  41. //如果promise为reject(1)
  42. //输出为 onReejected1() 1