Promise基础知识+Async、Await

概念:

Promise:ES6新增的内置类(构造函数),用来规划异步编程代码,解决回调地狱等问题

语法:

let p1= new Promise([ executor ])

[ executor ]必须是一个函数,而且new Promise的时候会立即把其执行“同步”

私有属性:结果

[[PromiseState]]: "pending、fulfilled、rejected"实例的状态;

[[PromiseResult]]: undefined 实例的值 [成功的或失败的原因]

公共方法:

Promise.prototype : then  catch finally ,.....

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

[ onfulfilled ],[ onrejected ]都是函数 

实例状态是成功fulfilled的时候,会把[ onfulfilled ]执行,并且把实例的值作为成功的结果传递给他

实例状态是失败rejected的时候,会把 [onrejected]执行,把实例值作为失败原因传递给他        

如何修改实例的状态和值

@1 基于这种方式创建实例

        let p=new Promise( ( resolve,reject ) => {

        .....

        } )

+  如果executor函数执行报错,则把实例的状态修改为rejected,值是报错原因 [ 不会抛异常 ]

+ resolve/reject也是函数

  resolve('ok') -> 把实例p的状态修改为 fulfilled ,值(成功结果)是'ok'

  reject('no') -> 把实例p的状态修改为 rejected,值(失败原因)是'no'

+ 一旦状态被修改为 fulfilled 或 rejected, 后期就不会再更改状态值了

@2 每一次执行then 方法,都会返回一个 “ 全新的Promise实例 ” 

let p2=p1.then ( onfulfilled , onrejected )

不论onfulfilled还是onrejected执行(由P1状态来决定),方法的执行决定了P2的状态和值

+ 首先看方法执行是否报错,如果报错了,则p2是失败(rejected),值是报错原因

+ 如果执行不报错,再看方法的返回值

        + 如果返回的是“新promise实例 -> @np”,则@np的状态和值直接决定了 p2的状态和值

        + 如果返回的不是新实例,则p2状态是成功(fulfilled),值是函数的返回值

@3 执行Promise.resolve / reject / all / any / race ...等静态私有方法,也会创建新的Promise实例

        + Promise.resolve(10) 创建一个状态是成功 fulfilled ,值是10的实例

        + Promise.reject(0) 创建一个状态是失败 rejected, 值是0的实例

  then链的穿透/顺延机制

    .then(onfulfilled,onrejected),两个方法可以传可以不传,如果不传,则顺延至下一个then中,相同状态要执行的方法中去处理!!

    + 原理:我们不设置对应的方法,PROMISE内部会默认加一个对应的方法,可以让其实现状态的顺延/穿透

    ---

    p.catch(onrejected) 等价于 p.then(null,onrejected)

这里null 默认的是 value => return value 

真实项目中:then中一般只传递onfulfilled「成功干什么」,最后加一个catch;这样不论中间哪个环节创建了失败的实例,都会穿透至最后一个catch;catch不加,出现失败的实例,控制台报“红”,但是不影响其他代码执行!!

Promise.reject(0)
    .then(
        null
        /!* value=>{
            return value;
        } *!/
        /!*,reason=>{
            throw reason;
        } *!/
    )
    .then(value => {
        console.log('成功', value);
    }, reason => {
        console.log('失败', reason);
    }); 

真实项目中:then中一般只传递onfulfilled「成功干什么」,最后加一个catch;这样不论中间哪个环节创建了失败的实例,都会穿透至最后一个catch;catch不加,出现失败的实例,控制台报“红”,但是不影响其他代码执行!!
Promise.resolve(10)
    .then(value => {
        console.log('成功', value);
        return value * 10;
    })
    .then(value => {
        console.log('成功', value);
        return Promise.reject(value * 10);
    })
    .then(value => {
        console.log('成功', value);
        return value * 10;
    })
    .catch(reason => {
        console.log('失败', reason);
    })
    .finally(()=>{
        //不论成功还是失败,最后都有要执行finally中的方法「一般不用」
    }); 

  关于Promise.all/any/race三个方法的研究

    let p = Promise.all/any/race([promises]);

      + promises是包含零到多个promise实例的集合,一般是数组!如果集合中的某一项不是promise实例,则默认变为状态为成功,值是本身的promise实例!!

      + all:集合中的“每个实例都成功”,最后结果p才成功,值是按照集合顺序,依次存储每个实例成功结果的数组;其中只要有一个实例失败,则p就是失败的,值是本次失败的原因,后面的操作不再处理!!

      + any:只要有一个成功,最后p就是成功的,值是本次成功的结果;都失败,最后p才是失败!{兼容性不好}

      + race:集合中谁最先知道结果,则以谁的为主!

let p1 = new Promise(resolve => {
    setTimeout(() => {
        resolve(1);
    }, 3000);
});
let p2 = new Promise(resolve => {
    setTimeout(() => {
        resolve(2);
    }, 2000);
});
let p3 = Promise.resolve(3);
let p4 = 4; //默认变为 -> Promise.resolve(4)

let p = Promise.all([p1, p2, p3, p4]);
p.then(values => {
    console.log(values); //1 2 3 4
}).catch(reason => {
    console.log('失败', reason);
}); 

  AJAX的串行和并行:真实项目中发送ajax请求都是“采用异步编程”

    并行:多个请求同时发送即可,谁先回来先处理谁,主要用于多个请求间没有依赖「偶尔我们需要监测,多个请求都成功,整体再去做啥事 => Promise.all」

    串行:多个请求之间存在依赖,上一个请求成功,我们才能发送下一个请求(往往是下一个请求需要用到上一个请求的结果,才需要这样处理)!

// AJAX并行
$.ajax({
    url: '/api1',
    success(result) {
        console.log(`第一个请求成功:`, result);
    }
});
$.ajax({
    url: '/api2',
    success(result) {
        console.log(`第二个请求成功:`, result);
    }
});
$.ajax({
    url: '/api3',
    success(result) {
        console.log(`第三个请求成功:`, result);
    }
}); 

// JQ中的AJAX串行 -> 回调地狱
$.ajax({
    url: '/api1',
    success(result) {
        console.log(`第一个请求成功:`, result);
        $.ajax({
            url: '/api2',
            success(result) {
                console.log(`第二个请求成功:`, result);
                $.ajax({
                    url: '/api3',
                    success(result) {
                        console.log(`第三个请求成功:`, result);
                    }
                });
            }
        });
    }
}); 
*/

// 基于Promise解决了串行中的回调地狱问题
axios.get('/api1')
    .then(value => {
        console.log(`第一个请求成功:`, value);
        return axios.get('/api2');
    })
    .then(value => {
        console.log(`第二个请求成功:`, value);
        return axios.get('/api3');
    })
    .then(value => {
        console.log(`第三个请求成功:`, value);
    });

Async、Await

async/await:是Promise+Generator的“语法糖”

   async是对函数的修饰 -> async function xxx(){...}

     + 让函数的返回值自动变为promise实例

       + 函数执行报错,则返回状态是rejected,值是报错原因的实例

       + 如果执行不报错,再看返回值

         + 返回值是新的实例,则以自己返回的promise实例为主

         + 其它情况都返回一个状态是fulfilled,值是返回值的实例

     + 可以在函数中使用await

   await可以监听promise实例的状态,从而决定去做啥事 -> let xxx = await [promise实例];

     + 必须出现在一个函数中,并且是经过async修饰的函数

     + await后面需要跟一个promise实例「如果不是promise实例,浏览器也会把其变为promise实例」

       await 14; => await Promise.resolve(14);

     + await会“等待”后面实例的状态为“成功”时,再把“当前上下文”中,await“下面”的代码执行!xxx就是实例状态为成功返回的结果!

     + 如果await后面的实例状态是失败,则下面代码不会执行(控制台爆红,但是不影响其它代码执行)!!

     + 我们是基于try/catch实现对await后面实例为失败态的处理,避免爆红

需求:设置三个定时器{2000,1000,3000},类似于ajax串行(第一个定时器触发后才能设置第二个...)

/* setTimeout(() => {
    console.log('第一个定时器触发执行');
    setTimeout(() => {
        console.log('第二个定时器触发执行');
        setTimeout(() => {
            console.log('第三个定时器触发执行');
        }, 3000);
    }, 1000);
}, 2000); */

const sleep = (interval = 1000) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, interval);
    });
};

/* const handler = async () => {
    await sleep(2000);
    console.log('第一个定时器触发执行');

    await sleep(1000);
    console.log('第二个定时器触发执行');

    await sleep(3000);
    console.log('第三个定时器触发执行');
};

函数用async修饰返回promise实例:fulfilled  10 

不用return返回也是promise实例 : fulfilled  undefined

const fn = async () => {
    // return Promise.resolve(100);
};
console.log(fn()); //返回promise实例:fulfilled undefined 

不知道请求结果之前,当前上下文await下面的代码是不会执行;只有后面实例状态是成功,下面代码才执行;如果实例状态是失败,下面代码也不执行「因为我们没有做失败情况的处理,所以控制台抛红」 可以使用 try/catch

(async function () {
    /* try {
        let result = await query(); //在不知道请求结果之前,当前上下文await下面的代码是不会执行;
        只有后面实例状态是成功,下面代码才执行;如果实例状态是失败,下面代码也不执行
        「因为我们没有做失败情况的处理,所以控制台抛红」
        console.log('请求成功:', result);
    } catch (reason) {
        // 实例状态是失败
        console.log('请求失败:', reason);
    } */

    /* 
    query()
        .then(result => {
            console.log('请求成功:', result);
        })
        .catch(reason => {
            console.log('请求失败:', reason);
        }); 
    */
})();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值