• 理解Promise对象


    Promise对象:

    • 一个保存异步操作事件的对象
    • 三种状态,Pending、Fulfilled、Rejected。状态只会由“Pending→Fulfilled”或者“Pending→Rejected”,且状态改变就不会再变
    /*Promise对象是由一个构造函数生成实例,接受函数为参数
       函数的参数为resolve和reject。这两者,也是函数*/
       
    var promise = new Promise ( function(resolve , reject){
        
        /*一些异步操作*/
        
        if/*异步操作成功*/){
            //当调用resolve函数的时候,Promise对象状态由,Pending → Fulfilled
            //将value值进行传递(一般是异步操作成功后的结果)
            resolve(value)
        }  
        else {
            //当调用reject函数的时候,Promise对象状态由,Pending → Rejected
            //将error值进行传递
            reject(error)
        }    
    })    

    总体上来说,Promise对象,更像是一个事件的容器,但Promise对象状态的改变并不受事件的完成而完成,而是由参数函数中的 resolve 和 reject 函数来指定它什么时候改变状态。

    比如下面代码:

    var promise = new Promise ( function(resolve , reject){
    
        let i = 0//标记事件已完成,传字符串resolved值给.then()处理
        resolve(i)
    i += 1 }) .then( //then方法是指,当Promise状态由Pending改变为Resolved时,立即调用 (value) = > { console.log(value) } )

    ---------------------------------------------------------------
    最后输出:
    0

    then()方法下面会继续讲,问题来了,上面代码“ i += 1”是否会运行呢?再看

    var promise = new Promise ( function(resolve , reject){
    
        resolve()
        console.log('A')
        setTimeout(() => { console.log('B') }, 3000)
    
    }) .then(() = > { console.log('Resolved') })
    ---------------------------------------------------------------
    先后输出:
    A
    Resolved
    B   //3000ms后输出B

    Promise对象在状态改变后,内部的代码还是会运行。当内部同步任务全部执行完成后,再调用then()方法。因此前两行最先输出的是‘A’和‘Resolved’,由于B是一个异步事件,所以在3000ms后被调用输出。

    如果想在状态改变后直接结束,不执行之后的语句,最好不要将异步操作放在状态改变语句之后!当然也可以这样:

    var promise = new Promise ( function(resolve , reject){
        //在前面加上return
        return resolve()
    
        console.log('A')
        setTimeout(() => { console.log('B') }, 3000)
    
    }) .then(() = > { console.log('Resolved') })
    ---------------------------------------------------------------
    最后只输出:
    Resolved

    原型方法 —— then()

    • 该方法是定义在Promise对象原型上的方法,即Promise.prototype.then()
    • 且then()方法返回一个新Promise实例

    顾名思义,Promise实例状态改变后,要做什么。该方法为其添加了回调函数。Promise实例有两种状态,自然也提供了两种回调(Resolved 和 Rejected)

    上面已经简单涉及了该方法,这里整理一下:

    var promise = new Promise ( function(resolve , reject){
        //做些什么...
        if/*异步操作成功*/){ resolve(value) }  
        else {  reject(error) }    
    }) .then( 
        //then方法接受两个回调函数为参数,以下
    
        //第一个Promise实例变为Resolved状态调用
        //函数中的参数value,接受Promise实例中resolve(value)传递的value值
        (value) => { /*success*/ },
    
        //(可选)第二个Promise实例变为Rejected状态调用
        ////函数中的参数error,接受Promise实例中reject(error)传递的error值
        (error) = > { /*failure*/ }
    )
    • then()的链式调用

    上面说了then方法返回一个新的Promise实例,那么就可以promise.then().then().then().then().then().....这样的链式调用了。

    var promise = new Promise ( function(resolve , reject){
        resolve(A)   
    }) .then( (value) => {  //此处参数 value 接受 resolve(A) 中的传递值 A
        //输出A
        console.log(value)
        return B
    }).then( (value) => {  //此处参数 value 接受上一级then()方法中return的值
        //输出B
        console.log(value)
    }).then( (value) => {  //上一个then方法无return时
        //输出undefined
        console.log(value)
    })
    -----------------------------------------------------------------
    先后在控制台上输出:
    A
    B
    undefined

    若then()方法中传入的不是函数,则在链式调用中,此then()方法会被忽略,值会传入下一个then方法中

    var promise = new Promise ( function(resolve , reject){
        resolve(A)   
    }) .then(1)  //这个then方法被忽略
      .then( (value) => {console.log(value)}  )
    -----------------------------------------------------------------
    控制台上输出:
    A

     

    原型方法 —— catch()

    • Promise对象原型方法,Promise.prototype.catch()
    • 等同于.then( null , reject(error) )
    • catch()方法返回一个Promise对象

    一般应用如下

    var promise = new Promise ( function(resolve , reject){
        if/*异步操作成功*/){ resolve(value)}  
        else { reject(new Error ('promise'))}    
    }) .then( (value)=>{
        if/*异步操作成功*/){ return A }  
        else { throw new Error('error_A') }  
    }).then( (value)=>{
        if/*异步操作成功*/){ return B }  
        else { throw new Error('error_B') }  
    }).then( (value)=>{
        if/*异步操作成功*/){return C }  
        else { throw new Error('error_C') }  
    }).catch( (error)=>{
        /*此处catch捕获以上从Promise对象到任意then方法所抛出的错误*/
        console.log(error) 
        //catch只能捕获被调用之前抛出的错误,之后的错误如'error_D'就无法捕获
    }).then( (value)=>{
        //上面的catch返回一个Promise对象因此可以继续调用then方法 
        if/*异步操作成功*/){return D }  
        else { throw new Error('error_D') }  
    })

    静态方法

    • Promise.all()
    • Promise.race()
    • Promise.resolve()
    • Promise.reject()

    Promise.all()

    将多个Promise实例包装,并且返回一个新的Promise实例

    当包装中所有的Promise状态都变为Resolved时,返回结果数组,数组中返回值的顺序安装包装的数据排列

    Promise.all([
       promise_A,
       promise_B,
       promise_C 
    ]).then(result=>{
      console.log(result)
    })
    ---------------------------
    //当promise_A,promise_B,promise_C状态都为Resolved时,result输出一个结果数组:
    [result_A,result_B,resultC]

    当Promise集合中有一个Promise最终状态为Rejected,就会被Promise.all()的catch方法进行捕获

    Promise.all([
          new Promise((resolve, reject) => {
            setTimeout(() => {
              console.log('A')
              reject(new Error('AAAAAAAAAAA'))
            }, 5000)
          }),
          new Promise((resolve, reject) => {
            setTimeout(() => {
              console.log('B')
              reject(new Error('BBBBBBBBBBB'))
            }, 2000)
          }).catch(e => {
            return e
          })
        ]).then(result => {
          console.log(result)
        }).catch(e => {
          console.log(e)
        })
      }
    
    ----------------------------------------------
    控制台先后输出:
    B            //2s后输出B
    A            //5s后输出A
    AAAAAAAAAAA            //A输出后立即输出错误'AAAAAAAAAAA'

     上面代码中为什么Promise. all最后捕获的是错误'AAAAAAAAAAA'而不是‘BBBBBBBBBBB’。因为在第二个Promise实例中,2秒后虽然状态变为Rejected并且抛出了Error,但是被自身之后的catch方法捕获了该错误且return。之前已经知道,Promise之后的then和catch方法其实返回的是一个新的Promise实例,若方法中没有抛出新的错误,其后续的状态就会变为Resolved。而第一个实例抛出错误后,并未被后续方法捕获,最后状态为Rejected,错误最终被外层Promise. all方法的后续catch所捕获,最后输出'AAAAAAAAAAA'。

    Promis.race()

    与上面方法一样,同样将多个Promise实例包装成一个新的Promise实例。

    Promise.race([P1,P2,P3])
        .then( value => { /*do something*/ } )
        .catch(e => { /*do something*/ })

    Promise实例组中,P1、P2、P3谁的状态先发生变化(Resolved 或 Rejected),Promise.race()状态也发生改变,P1(or P2 or P3)的返回值传递给Promise.race()回调函数。

    Promise.resolve()

    将一个对象转为一个Promise对象,以下几种情况

    let p = new Promise( (resolve,reject) => { resolve(1)} )
    //传入Promise对象p,返回还是p
    Promise.resolve(p)

    //传入一个非thenable对象(thenable对象,就是一个对象具有then方法,下面会说明),或者非对象
    Promise.resolve('_JayKoo')
    --------------------------------------
    //上面代码等同于
    new Promise( (resolve,reject) =>{
        resolve('_JayKoo');
    })

    //thenable对象,具有then方法的对象
    //then方法满足以下格式
    let obj = {
        then(res , rej){     //then函数,参数满足Promise回调函数中的参数格式。then函数,相当于,Promise构造函数中的回调函数格式。
            if(/*Resolved*/){ res(value) }
            else { rej(error) }
        }
    }
    
    //将obj转为Promise对象,且立即调用then方法
    Promise.resolve( obj )
    ---------------------------------------------------------------------------
    //以上代码的效果等同于立即执行了
    new Promise( (res, rej) => {
        /*obj对象中的操作*/
        if(/*Resolved*/){ res(value) }
        else { rej(error) }
    })

    //不带参数,立即生成一个Promise对象
    //Promise.resolve()方法的执行,是在本轮注册的所有同步脚本事件的结束时(非异步)
    let p = Promise.resolve()

    Promise.reject()

    Promise.reject()同样返回Promise对象.。

    在Promise.resolve()中,传入的参数由thenable对象和非thenable对象两种情况,且之后的参数调用情况也不同。

    但在Promise.reject()中,所有传参都会被当做Error抛出。

    let p = Promise.reject(thenable)
    --------------------------------------
    //等同于
    let p = new Promise( (resolve,reject) => {
        //即使是个thenable对象,也会原封不动地将这个对象当做错误信息抛出
        reject(thenable)
    })
    --------------------------------------
    p.catch( e => {
       console.log( e === thenable) 
    })
    //true
  • 相关阅读:
    自然二进制与格雷码的转换
    状态机小结
    FSM的几种策略
    跨越鸿沟:同步世界中的异步信号
    边沿检测技术
    门控时钟和时钟使能
    ALTERA器件中复位电路实现之-异步复位同步化
    同步复位
    Altera USB Blaster 仿真器(EPM240仿制版
    五、裸机烧写
  • 原文地址:https://www.cnblogs.com/jaykoo/p/10007910.html
Copyright © 2020-2023  润新知