Promise是异步问题同步话的一个解决最优方案、在前很多年的时候一般异步处理的方式大多都是callBack形式、因为callBack的形式也会导致无法通过return的形式把结果返回出去、还有一个就是callBack过多会导致地狱嵌套严重的问题、promise还封装了多个异步同时执行的能力、通过Promise我们能够写出更优雅的异步解决方案!

Promise状态

  • pending (初始化-等待执行)
  • fulfilled (执行成功)
  • rejected (操作失败)

    每种状态执行完都会触发对应的 链式方法、promise只允许一种状态要么成功要么失败

  1. /* 成功案例 */
  2. let p = new Promise( (resolve) =>{
  3. setTimeout(() => { resolve(1) }, 100);
  4. })
  5. console.log(p) // Promise {<pending>}
  6. // 通过then接收执行成功的结果
  7. p.then( res =>{
  8. console.log(res); // 1秒后得到 1
  9. console.log(p) // Promise {<fulfilled>: 1}
  10. return new Promise( resolve =>{
  11. setTimeout( () => resolve({'name':'张三'}) , 2000)
  12. })
  13. }).then( res =>{
  14. console.log(res); // {name: '张三'}
  15. return {
  16. age:100
  17. }
  18. })
  19. .then( res =>{
  20. console.log(res) // {age: 100}
  21. })
  22. .finally( () =>{ //不管成功或失败都会执行
  23. console.log('当前promise运行完成')
  24. })
  25. /* 失败案例 */
  26. let p2 = new Promise( (resolve, reject) =>{
  27. setTimeout(() => { reject('失败了') }, 1000);
  28. })
  29. console.log('p2',p2) // Promise {<pending>}
  30. p2.catch( err =>{
  31. console.log('err',err) // 失败了
  32. console.log('p2 status',p2) // p2 status Promise {<rejected>: '失败了'}nsole.log('err',err) // Uncaught (in promise) 失败了
  33. })

then也返回一个promise对象、是promise就 会存在then方法、在then方法里面直接return 或者返回一个promise状态都能够在继续使用.then方法进行接收、有点像俄罗斯套娃了、嵌套在一起!

promise.all()

接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型)、只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误、那这个Promise.all也会被标记reject状态

  1. let p1 = new Promise( resolve =>{
  2. setTimeout( () => resolve(1),1000)
  3. })
  4. let p2 = new Promise( resolve =>{
  5. setTimeout( () => resolve(2),1500)
  6. })
  7. let p3 = new Promise( resolve =>{
  8. setTimeout( () => resolve(3),2000)
  9. })
  10. Promise.all([ p1, p2, p3 ]).then( res =>{
  11. console.log(res) // [1, 2, 3]
  12. })
  13. .catch( err =>{
  14. console.log(err)
  15. })
  16. // 某个状态为reject
  17. let p4 = new Promise( resolve =>{
  18. setTimeout( () => resolve(1),1000)
  19. })
  20. let p5 = new Promise( (resolve,reject) =>{
  21. setTimeout( () => reject('失败了'),1500)
  22. })
  23. Promise.all([ p4, p5 ]).then( res =>{
  24. console.log(res)
  25. })
  26. .catch( err =>{
  27. console.log(err) // 失败了
  28. })

Promise.allSettled()

接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型)、返回每一个promise的状态和结果, 弥补了promise.all遇到reject就直接返回reject的问题、Promise.allSettled() 优于Promise.all

  1. let p4 = new Promise( resolve =>{
  2. setTimeout( () => resolve(1),1000)
  3. })
  4. let p5 = new Promise( (resolve,reject) =>{
  5. setTimeout( () => reject('失败了'),1500)
  6. })
  7. Promise.allSettled([ p4, p5 ]).then( res =>{
  8. /* 得到
  9. {status: 'fulfilled', value: 1}
  10. {status: 'rejected', reason: '失败了'}
  11. */
  12. console.log(res)
  13. })
  14. .catch( err =>{
  15. console.log(err)
  16. })

Promise.any()

接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型),只要其中的一个 promise 成功,就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝)就返回reject状态

  1. let p4 = new Promise( (resolve,reject) =>{
  2. setTimeout( () => resolve(1),2000)
  3. })
  4. let p5 = new Promise( (resolve,reject) =>{
  5. setTimeout( () => reject('失败了'),1500)
  6. })
  7. let p6 = new Promise( (resolve,reject) =>{
  8. setTimeout( () => resolve(2222),2500)
  9. })
  10. Promise.any([ p4, p5, p6 ]).then( res =>{
  11. console.log(res) // 1
  12. })
  13. .catch( err =>{
  14. console.log('err',err)
  15. })

Promise.race()

接收一个Promise可迭代(iterable)类型(注:Array,Map,Set都属于ES6的iterable类型),一旦迭代器的某个promise状态被返回(不管是reject还是resolve)都返回出去

  1. let p4 = new Promise( (resolve,reject) =>{
  2. setTimeout( () => resolve(1),2000)
  3. })
  4. let p5 = new Promise( (resolve,reject) =>{
  5. setTimeout( () => reject('失败了'),1500)
  6. })
  7. let p6 = new Promise( (resolve,reject) =>{
  8. setTimeout( () => resolve(2222),2500)
  9. })
  10. Promise.race([ p4, p5, p6 ]).then( res =>{
  11. console.log(res)
  12. })
  13. .catch( err =>{
  14. console.log('err',err) // err 失败了
  15. })

Promise.resolve

把一个结果包装成一个成功的promise、即可使用then接收、场景可用来组装参数同步化一次性返回出去

  1. let use = {name:'zhangsan'}
  2. let p1 = new Promise( resolve => resolve(2))
  3. let p = Promise.all([ Promise.resolve(use), p1]);
  4. p.then( res =>{
  5. console.log(res)
  6. })

Promise.reject()

把一个结果包装成一个失败的promise、即可使用catch接收

  1. let use = {name:'zhangsan'}
  2. let p1 = new Promise( resolve => resolve(2))
  3. let p = Promise.race([ Promise.reject(use), p1]);
  4. p.then( res =>{
  5. console.log(res)
  6. })
  7. .catch(err =>{
  8. console.log(err) // {name: 'zhangsan'}
  9. })

异步问题同步化方案

上面案例都是基于异步的then方式接收结果、那有没有可以和同步代码并行执行呢、答案是:可以的

async await
  1. let p1 = new Promise( resolve =>{
  2. setTimeout( () =>{
  3. resolve('2s的结果')
  4. },2000)
  5. })
  6. async function start(){
  7. console.log(1)
  8. let res = await p1;
  9. console.log(res);
  10. console.log(2)
  11. }
  12. start()
  13. // 1
  14. // 2s的结果
  15. // 2

经典面试题

  1. Promise.resolve().then(() => {
  2. console.log(0);
  3. return Promise.resolve(4);
  4. }).then((res) => {
  5. console.log(res)
  6. })
  7. Promise.resolve().then(() => {
  8. console.log(1);
  9. }).then(() => {
  10. console.log(2);
  11. }).then(() => {
  12. console.log(3);
  13. }).then(() => {
  14. console.log(5);
  15. }).then(() =>{
  16. console.log(6);
  17. })
  18. // 0
  19. // 1
  20. // 2
  21. // 3
  22. // 4
  23. // 5
  24. // 6
  25. /*
  26. Js引擎为了让microtask尽快的输出,做了一些优化,
  27. 连续的多个then(3个)如果没有reject或者resolve会交替执行then而不至于让一个堵太久完成用户无响应,不单单v8这样其他引擎也是这样,
  28. 因为其实promuse内部状态已经结束了。这块在v8源码里有完整的体现
  29. 来自:https://juejin.cn/post/6945319439772434469#heading-31
  30. */