0
点赞
收藏
分享

微信扫一扫

这一次,彻底搞懂Promise

程序猿不脱发2 2022-03-11 阅读 65

一、为什么要引入Promise

  • Promise解决了什么问题?
  • Promise有哪些具体的使用场景?

Promise解决了什么问题?

  1. 回调地狱问题
// 回调地狱实例

// 奶茶函数
function getTea(fn) {
  setTimeout(() => {
    fn('获取到一杯奶茶')
  },2000)
}

// 面包函数
function getBread(fn) {
  setTimeout(() => {
    fn('获取到一个面包')
  },100)
}

// 如果必须按照顺序获取,而不是根据时间,要求是先获取到奶茶后获取到面包。
getTea(function(data) {
  console.log(data);
  getBread(function(data) {
    console.log(data);
  }) 
})
  1. 可读性问题
// 下面解释下,如何通过Promise来解决回调地狱的问题
function getTea() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('获取到一杯奶茶')
    }, 2000)
  })
}

function getBread() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('获取到一个面包')
    }, 500)
  })
}

getTea()
  .then(res => {
    console.log(res);
    return getBread();
  })
  .then(res => {
    console.log(res);
  })
  1. 信任问题(也叫回调多次执行问题)

Promise有哪些具体的使用场景?

  • 场景1:将图片的加载写成一个Promise,图片一旦加载完成,Promise的状态就会发生变化。
  • 场景2:当下一个异步请求需要依赖上一个请求结果的时候,可以通过链式操作解决问题。
  • 场景3:通过all()实现多个请求合并在一起,汇总所有的请求结果,只需设置一个loading即可。
  • 场景4:通过race()可以设置图片请求超时。

二、手写Prromise身上的方法

手写Promise.all

function myPromiseAll(iterable) {
  // 首先明确要返回的对象是一个Promise
  return new Promise((resolve,reject) => {
    // 首先将可迭代对象转换为数组
    const promises = Array.from(iterable);
    let flag = 0;
    const result = [];
    // 开始遍历执行
    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then(res => {
        result[i] = res;
        flag++;
        if (flag === promises.length) {
          resolve(result)
        }
      }).catch(err => {
        reject(err)
      })
    }
  })  
}

手写Promise.race

// 手写promise.race
function myPromiseRace(iterator) {
  // 首先返回的是一个promise对象
  return new Promise((resolve,reject) => {
    for (let item of iterator) {
      Promise.resolve(item).then(res => {
        resolve(item);
      }).catch(err => {
        reject(err);
      })
    }
  })
}

let p1 = new Promise(resolve => {
  setTimeout(resolve, 105, 'p1 done')
})
let p2 = new Promise(resolve => {
  setTimeout(resolve, 100, 'p2 done')
})
myPromiseRace([p1, p2]).then(data => {
  console.log(data); // p2 done
})

手写Promise.finally

  • 无论成功还是失败,都会执行这个方法
  • 返回的是一个Promise
let p = new Promise((resolve,reject) => {
  setTimeout(() => {
    resolve(111);
  },2000)
})

p.then(res => {
  console.log(res);  // 111
}).finally(() => {
  console.log('无论如何这里都会被执行');  // 无论如何这里都会被执行
})
Promise.prototype.finally = function(f) {
  return this.then((value) => {
    return Promise.resolve(f()).then(() => value)
  },(err) => {
    return Promise.resolve(f()).then(() => {
      throw err;
    })
  })
}

Promise.all和Promise.race的区别

Promise.all和Promise.race的应用场景

promise.all()的应用场景

  • 多个异步任务都得到结果时,进行显示的场景

Promise.race()的应用场景

  • 提示用户请求超时

三、Promise是如何解决串行和并行的?

什么是并行?什么是串行?

Promise实现并行请求

Promise实现串行请求

// 借助reduce函数来实现Promise的串行执行
const funcArr = [
  () => {
    return new Promise((resolve) => {
      setTimeout(() => {resolve(1)},2000)
    })
  },
  () => {
    return new Promise((resolve) => {
      setTimeout(() => {resolve(2)},1000)
    })
  },
  () => {
    return new Promise((resolve) => {
      setTimeout(() => {resolve(3)},3000)
    })
  },
];

function inOrder(arr) {
  const res = [];
  return new Promise((resolve) => {
    arr.reduce((pre,cur) => {
      return pre.then(cur).then(data => res.push(data))
    },Promise.resolve()).then(data => resolve(res))
  })
}

inOrder(funcArr).then(data => console.log(data))   // [1,2,3]

四、什么是Promise穿透?

Promise.resolve(1)
  .then(function(){return 2})
  .then(Promise.resolve(3))
  .then(console.log)   // 2

五、使用Promise封装Ajax请求

// 使用Promise封装Ajax请求
const res = new Promise((resolve,reject) => {
  // 1. 创建一个XMLHttpRequest对象
  const xhr = new XMLHttpRequest();
  // 2. 初始化请求方法和URL
  xhr.open('GET','https://api.apiopen.top/getJoke');
  // 3. 发送请求
  xhr.send();
  // 4. 绑定事件,处理响应结果
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      // 这里4代表的就是说服务端返回了全部的结果
      // 如果服务端返回的状态码是2开头的,我们就resolve这个返回的结果,反之则reject对应的状态码
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response)
      } else {
        reject(xhr.status)
      }
    }
  }
})
res.then(function(value) {
  console.log(value);
},function(err) {
  console.log(err);
})

六、Promise有哪些状态?

  • pending状态(初始状态)
  • fulfilled状态(已经成功的状态)
  • rejected状态(已经失败的状态)

Promise状态的变化过程

  1. 从pending到fulfilled状态的切换
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('resolve前的状态:', p);
    resolve();
    console.log('resolve之后的状态', p);
  })
})

image.png

  1. 从pending状态到rejected状态
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('reject前的状态:', p);
    reject();
    console.log('reject之后的状态', p);
  })
})

image.png

七、将callback改写成Promise

  1. 传统callback的形式

    const fs = require(‘fs’);

    fs.readFile(’./temp.md’,(err,data) => {
    console.log(data.toString());
    })

  2. 将callback改为promise的形式

const fs = require('fs');

async function myReadFile() {
  let result = await new Promise((resolve,reject) => {
    fs.readFile('./temp.md',(err,data) => {
      resolve(data.toString());
    })
  })
  console.log(result);   // xxxxx
  return result;
}

myReadFile()
举报

相关推荐

0 条评论