Promise详解

一、发展

直接使用传统回调方式去完成复杂的异步流程,无法避免大量的函数嵌套,就会导致函数回调地狱问题,为了避免回调地狱问题,CommonJS社区提出了promise规范,目的就是为异步编程一共一种更合理更强大的解决方案,后来在ES2015中被标准化,成为语言规范,也就是ES6中的promise对象。

二、概念

Promise对象用于异步操作,表示一个尚未完成且预计在未来完成的异步操作。异步过后会返回成功或者失败两个状态。

promise中的resolve就是将pending变成fulfilled(未完成变成成功),reject就是将状态从pending变成rejected(未完成变成失败)。一旦状态改变,就不会再变,任何时候都可以得到这个结果,最后都会有相应的操作。

三、Promise的三个状态

1、pending:待定,初始状态,不是成功或失败状态。
2、fulfilled:完成,意味着操作成功完成。
3、rejected:被否决,意味着操作失败。

四、Promise 优缺点

优点:可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

缺点:无法取消 Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部,当处于 Pending 状态时,无法得知目前进展到哪一个阶段。

五、Promise的基本用法

const promise = new Promise (function (resolve, reject) {
  // 只能调用其一
  resolve(100) // 承诺成功
  reject(new Error('promise rejected')) // 承诺失败

})

// then中第一个函数就是成功后的回调函数,第二个就是失败后的回调函数
promise.then(function (params) {
  console.log('resolved', params)
}, function (err) {
  console.log('rejected', err)
})
//如果promise中没用任何异步操作,then中任务任进入到queue中进行排队,必须要等待同步代码全部执行完了,才会执行then中的任务

六、promise案例

function ajax (url) {
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest()
    xhr.open('GET', url)
    xhr.responseType = 'json'
    xhr.onload = function () {
      if (this.status === 200) {
        resolve(this.response)
      } else {
        reject(new Error(this.statusText))
      }
    }
    xhr.send()
  })
}

ajax('/api.json').then(res => {
  console.log(res, 'res')
}, err => {
  console.log(err, 'err')
})

七、Promise链式调用

ajax('/api.json')
  .then(res => {
    console.log(res, 'res')
  }) // => promise
  .then(res => {
    console.log(res, 'res1')
  })
  .then(res => {
    console.log(res, 'res2')
  })
  .then(res => {
    console.log(res, 'res3')
  })
  .then(res => {
    console.log(res, 'res4')
  })

每一个then方法都是在为上一个then返回的promise对象添加状态后的回调,这些promise会依次执行。then中如果没有返回值默认的就是undefined

Promise对象的then方法会返回一个全新的Promise对象

后面的then方法就是在为一个then返回的Promise注册回调

前面then方法中回调函数的返回值作为后面then方法回调的参数

如果回调中返回的是Promise,那后面then方法的回调会等待它的结束

八、异常处理

1.onRejected回调就是为promise中的异常做出处理,在promise中调用不存在的方法或者手动抛出一个错误(throw new Error())等异常或者promise失败了都会触发onRejected回调。

2.可以用then方法注册成功的回调,用catch方法注册失败onrejected回调,也可以用then中的第一个参注册成功回调,第二参注册失败回调。

3.catch方法也类试于then方法第一参传递了一个undefined,第二参失败回调。

4.catch方法和then方法第二参直接注册失败回调的差异

   每个then方法返回的都是一个全新的Promise对象,也就是说我门通过链式调用的方式调用catch实际上是在给前面then方法返回的全新Promise去指定失败的回调,并不是直接给第一次promise对象所指定的,因为这是同一个promise链条,那前面promise上的异常会一直往后传递,所以catch才可以捕获到第一个promise上的异常。

   而通过then方法的第二个参数去指定的失败回调函数,那它只是给第一个promise指定的,也就是它只能捕获到这个promise上的异常。

   在表象上的差异,如果在then方法当中返回了第二个promise,而且这个promise执行过程当中出现了异常,如果在第一个promise中then的第二个参数上注册的失败回调,是捕获不到第二个promise上的异常,因为它只是在第一个上面注册的失败回调。使用catch的话就可以捕获到,因为这样失败回调就是绑定在then返回的promise上面。

  在链式的调用上去分开指定成功和失败的回调,因为promise链条上任何一个异常都会向后传递,直到被捕获

5.unhandledrejection

unhandledrejection去处理一些我们代码当中没有被手动捕获的promise异常。

在浏览器当中把这个事件注册在window对象上

  window.addEventListener('unhandledrejection', event => {
    const { reason, promise} = event
    // reason => Promise 失败原因,一般是一个错误对象
    // promise => 出现异常的promise对象
    event.preventDefault()
  }, false)

在node当中需要在process.on对象上去注册 

九、promise的静态方法

1.Promise.resolve():快速的把一个值转换为promise对象

  Promise.resolve('foo').then(res => {
    console.log(res) // foo
  })
// foo就会做为这个promise对象返回的值

// 与下面例子是等价的
new Promise((resolve, reject) => {
  resolve('foo')
})

如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。

如果Promise.resolve方法的参数是一个Promise对象的实例,则会被原封不动地返回。

如果resolve参数是一个key为then的对象,这样一个值也可以做为promise对象被执行

Promise.resolve({
  then: function (onFulfilled, onRejected) {
    onFulfilled('foo')
  }
}).then(value => {
  console.log('value') // foo
})

2.Promise.reject():快速创建一个是失败的promise对象

Promise.reject(new Error()).catch(err => {
  console.log(err)
})
// reject的参数就是回调函数返回的值

3.Promise.all()方法

Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例统一去管理,用于多个promise并行执行时统一管理。

promise的all方法接受的是一个数组,数组中的元素都是Promise对象的实例(Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例。)

all方法会返回一个全新的promise对象,当内部所以的promise都完成之后返回的这个全新promise才会完成,那么这个promise拿到的结果就是一个数组,包含的每个promise执行完的结果,当其中一个失败了,这个新的promise就会以失败结束。

var p = Promise.all([p1,p2,p3]);

4.Promise.race()方法

race方法同样可以讲多个Promise对象组合成一个全新的promise对象

all方法会等待所有任务结束,race只会等待第一个结束的任务

十、promise执行顺序

回调队列中的任务称之为宏任务,宏任务执行过程中可以临时加上一些额外的需求,这些需求可以选择作为一个新的宏任务进到队列中排队,也可以作为当前任务的微任务

微任务直接在当前任务结束过后立即执行,而不是到整个队伍的末尾重新排队。是为了提高整体的响应能力

promise的回调会作为微任务执行的,所以它会再本轮调用的末尾去执行

settimeout以宏任务的形式进入到队列的末尾

目前绝大多数异步调用都是作为红任务执行,而Promise和MutationObserver,node中的process.nextTick会作为微任务在本轮调用的末尾执行。

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值