Promise相关

Promise相关

关于异步:

出现背景:

  • 由于JS是单线程语言,因此所有网络操作、浏览器事件都必须是异步执行的。

    异步解决方案:

    方案一:回调函数方式(注册-执行异步任务-触发回调函数)
    原理:
  • 浏览器解释执行js代码过程中,遇到异步任务,首先在系统中挂起(异步队列中注册回调函数),当异步任务(eg:I/O,网络请求等操作完成之后),通过触发回调函数的方式完成整个异步操作。

    异步的问题:
  • 传统采用回调函数处理异步任务的方式可以处理问题,但可能进入回调地狱,剥夺return的权利
  • 回调方式,代码嵌套层次深,易读性差,且不易维护

    场景:
  • setTimeOut
  • ajax请求


方案二:Promise方式

概念:

  • Promise是一个对象:承诺将来会执行的对象(代表异步操作最终成功或者失败)
  • promise作为队列最为重要的特性,我们在任何一个地方生成了一个promise队列之后,我们可以把他作为一个变量传递到其他地方。
  • 三种状态:pending、fulfilled、rejected
  • 两类函数:resolve(),将pending状态变为fulfilled状态,rejecte(),将pending状态变为rejected状态
  • thenable对象:具有特定格式then属性的对象

    约定(与传统回调函数不同):

  • 本轮Event Loop完成之前,回调函数不会被调用
  • then函数总会被调用,即使它是异步操作完成之后才添加的
  • 多次调用then,可以添加多个回调函数,它们会按照插入顺序,一个接一个独立执行
  • ** 因此,Promise最直接的好处是链式调用

问题场景:

then方法中返回的不是Promise对象
  • 若返回为空,程序默认返回值为null
  • 若返回其他非Promise对象,程序直接进入下一级then方法中
catch + then
  • catch只抓当前作用域的错误,过期不候
  • catch之后还可以继续执行then方法,但是跳过的方法将不再执行
  • 建议使用reject的方式抛出错误,而非new Error
console.log('程序开始执行')
new Promise((resolve)=>{
    setTimeout(()=>{
        resolve()
    },200)
})
.then(()=>{
    console.log('then_1开始执行')
    reject('then_1中执行了reject方法')
})
.then(()=>{
    console.log('then_2开始执行')
})
.catch((err)=>{
    console.log('I catch' + err)
})
.then(()=>{
    console.log('then_3开始执行')
})
.catch((err)=>{
    console.log('最终err未执行')
})

输出结果:
    程序开始执行
    then_1开始执行
    I catch then_1中执行了reject方法
    then_3开始执行

方法:

// 包装不支持Promise语法的函数
new Promise()
// 所有Promise任务执行完成才能执行then
// Promise对象组成的数组作为参数
Promise.all()
// 只要有其中一项完成,即可执行then
Promise.race()
// 手动创建一个resolve的Promise
Promise.resolve()
// 手动创建一个reject的Promise
Promise.reject()

Promise.prototype.then()
Promise.prototype.catch()
Promise.prototype.finally()

源码实现方式:

const PENDING = 'pending'; //初始状态
const FULFILLED = 'fulfilled'; // 成功状态
const REJECTED = 'rejected'; // 成功
function Promise(extutor){
  let self = this;
  self.status = PENDING; // 设置状态
  // 存放成功回调的数组
  self.onResolveCallbacks = [];
  // 存放失败回调的数组
  self.onRejectedCallbacks = [];
  function resolve(value){
    if(self.status === PENDING){
      self.status = FULFILLED;
      self.value = value;
      self.onResolveCallbacks.forEach(cb => cd(self.value))
    }
  } 
  function reject(reason){
    if(self.status === PENDING){
      self.status = REJECTED;
      self.value = reason;
      self.onRejectCallbacks.forEach(cb => cd(self.value))
    }
  } 
  try{
    excutor(resolve, reject)
  } catch(e) {
    reject(e)
  }
}

相关推荐