promise

183 阅读6分钟

promise

定义:

ES6新增的内置类,它是“承诺者模式”,主要是为了有效管理异步编程,避免“回调地狱”

  • 不兼容IE浏览器,如果想在IE当中使用她,需要基于ES5重写Promise「Promise A+规范 && 也可以基于babel/polyfill处理」

语法:

let p1 = new Promise([executor]);

[executor]

  1. 必须传递的是函数,不传或者传递其他类型值都会报错

  2. new Promise的时候,会立即把传递的[executor]函数执行,这个操作是同步的

  3. [executor]函数中

    @1 一般用来写一些异步的编程代码(promise管理异步编程,其实就是把异步编程的代码放在[executor]中)
    
    
    @2 [executor]函数中有两个形参:resolve / reject
    
          1) 本身也是函数
          2)resolve([value])把实例的状态改为fulfilled,实例值是[value]
          3reject([reason]),把实例的状态改为reject,实例值是[reason]
          4)一旦实例的状态被改变为失败或者成功,不可以再次更改
    
  4. [executor]函数执行一旦报错,实例的状态也是rejected,实例的值是报错原因

[p1 是 Promise类的一个实例]

  1. 私有属性

    •    [[PromiseState]]:"pending" 实例的状态
      
    •    ’pending‘最开始的默认值(准备状态)
      
    •    ‘fulfilled’或者‘resolved’ 成功态
      
    •    ‘rejected’失败状态
      
    •    [[PromiseResult]]:undefined 实例的结果(存储成功的结果或者失败的原因)
      
  2. 公有方法 Promise.prototype

  •    then
    
  •    catch
    
  •    finally
    
  •    symbol.toStringTag:"Promise"
    

new Promise();


`let p1 = new Promise((resolve,reject)=>{
   
   resolve(100)
  
  });

let p2 ==p1.then((value)=>{

    },
    (reason)=>{

    });
   p2.then(
    (value)=>{};
    (reason)=>{}
)    `

p1.then语法

p1.then([onfuifilled],[onrejected])

  1. [onfuifilled]和 [onrejected]一般都是一个函数
  2. 当实例的状态是fulfilled的时候,则会吧onfuifilled]的方法执行;实例状态是rejected的时候,则会吧[onrejected]的方法执行,如果实例状态还是pending,两个方法暂时都不会执行,只有等到等待状态修改后再执行对应方法
  3. 两个函数中的value或者reason存储的都是[[PromiseResult]]实例的结果~

执行then方法会返回一个全新的promise实例「例如p2

  1. 如何确定p2是成功还是失败的? 有P1.then 传入的[onfuifilled]或者[onrejected]任何一个方法执行决定
 @1 看方法执行是否报错,如果报错,则p2状态是rejected,值是报错的原因;如果没有报错则继续……
 @2 看方法执行的返回值是否是一个新的promise实例(别名:@PE),如果并没有返回新promise实例,则P2的状态是fulfilled,值是返回的值!!
   如果@PE是一个promise实例,则@PE的状态和值,直接决定来P2的状态和值!!

创建promise实例的4种方法

  1. let p1 = new Promise((resolve,reject)=>{ resolve(100)});

  2. let p2 ==p1.then

  3. promise.resolve([value])创建一个状态是fulfilled,值得[value]的实例

  4. promise.reject([reason])创建一个状态是rejected,值得[reason]的实例

then 链具备‘穿透性’

如果onfuifilled或者onrejected没有设置,则会顺延到下一个then对应的onfulfilled或者onfejected上

  • 原理:我们没有设置,promise内部会默认进行设置,以此来实现顺延

catch

  1. promise实例.catch([onrejected])等价于.then(null,[onrejected])

  2. 真实项目中:then一般只写onfulfilled方法,在整个“链”最末尾加一个catch处理失败,这样不论哪一次then中的方法执行结果是失败,都会走到最后一个catch中;如果实例状态是失败,但是我们没有设置任何失败处理的函数,则浏览器会抛出这个红色的错误,但是不会影响其他代码的处理!!

     `Promise.reject(0)
     .then(value=>{
      console.log('成功', value)
      return value*10
     })
     .then(value=>{
      console.log('成功', value)
      return value*10
    })
    .then(value=>{
     console.log('成功', value)
    return value*10
    })
    .catch(reason=>{
    console.log('失败',reason)
    })`
    

all,any,race

传递一个数组,数组中包含多个promise 实例,最后返回一个新的promise实例(别名:_NEW)

  1. 数组中某一项并不是promise实例,内部会把其处理为状态是成功,值是这个值的promise实例

  2. 返回的新实例_NEW是成功还是失败?

    •  promise.all 集合中所有实例都成功,整体(_NEW)才是成功,只要有一个失败,整体就是失败!!
      
    •  promise.any 集合中只要有一个成功,则整体就成功,除非所有的都失败,整体才失败!!
      
    • promise.race 看集合中谁第一个计算出结果和状态。那么他的状态和结果就是整体的状态和结果!!
      

Let _NEW = promise.all([promise1,promise2,...])

Let _NEW = promise.any([promise1,promise2,...])

Let _NEW = promise.race([promise1,promise2,...])

promise 执行的情况

示例

`let p1 = new Promise(resolve =>{

resolve('ok')//立即修改了P1的状态和值「同步」

});

console.log(3)

p1.then(value=>{

console.log('成功',value)

},reason=>{

console.log('失败',value)

})

console.log(4)`

详解

promise.then(onfuifilled,onrejected)

  情况一:

调用then的时候,promise的状态是已经知道成功或者失败的,也并不会把onfuifilled 和onrejected 立即执行,而是创建一个”异步的微任务“「先进入WebAPI中监听,发现后期肯定可以执行,则挪至到EventQueue中排队等着...等待同步代码执行完,在按照顺序执行异步任务」

情况二:

调用then的时候,promise的状态是pending,此时我们需要先把onfuifilled 和onrejected存储到对应的容器当中,同时把让“两个方法中的一个执行”这件事放在WebAPI中去监听,同步代码继续执行……

  当后期我们清楚的知道promise是成功还是失败的「例如:resolve和reject方法执行……」,把之前放在WebAPI中监听的任务,挪至到“异步的微任务队列中”排队等着(并不会立即执行)

为什么会有promise?promise可以有效管理异步编程

ajax请求(目的:从服务器获取数据,实现和服务器端的数据通信)

  • ajax串行:多个请求之间有依赖,只有完成上一个请求,才能发送在一个请求
  • ajax并行:多个请求之间并没有任何关系,此时我们可以同时发送多个请求,谁先请求回来数据,就先处理谁「额外的需求,同时发送多个请求,当所有的请求都成功,我们想要做啥事……」。

串行回调地狱example: 需求:三个请求借口:( ),对于异步编程来讲,如果基于回调函数的方式来处理异步成功后的相关操作,非常容易产生回调地狱,代码看起来太‘恶心’

 ` $.ajax({
  url:'/api/list'
  success(){
      //第一个请求成功,触发success回调函数
      $.ajax({
          url:'/api/detail?id=100'
          success(){
              //第二个请求成功,触发success回调函数
              $.ajax({

              })
          }
      })
  }
})

` 为了避免回调地狱的写法:

axios.get返回的是pormise 的实例,所以基于promise可以有效管理异步编程

` axios.get('/api/list') 
        .then(()=>{
   //第一个请求成功 
        return axios.get('/api/detail?id=100');
   })
       .then(()=>{
  //第二个请求成功 
     return axios.get('/api/paiming')
  })
       .then(()=>{
  //第三个请求成功
   })`

more sweet:

基于async/await语法糖,实现出把异步改为同步的效果

`async()=>{
 
 await axios.get('')

 await axios.get('')

 await axios.get('')
 }) `