Promise:工作流程、常见API、使用方法、手撕Promise、async/await


Promise指定回调函数的方式更加灵活,且支持链式调用,可以解决回调地狱的问题。

回调地狱:回调函数嵌套调用,外部回调执行结果是内部函数执行的条件,不便于阅读且不便于异常处理,解决方式就是promise(或async/await)

全部代码请见github:https://github.com/DantinZhang/customPromise

一、Promise的常见骚操作

0.初体验

先来看一个案例:抽奖

// 生成随机数
function rand(m,n) {
   
    return Math.ceil(Math.random() * (n-m+1) + m-1);
}

const p = new Promise((resolve, reject) => {
   
    setTimeout(() => {
   
        let n = rand(1, 100);
        if (n <= 30) {
   
            resolve(n); //把Promise对象的状态从未完成=>成功
        } else {
   
            reject(n);  //把Promise对象的状态从未完成=>失败
        }
    }, 1000);
});

Promise接收两个参数,分别是resolvereject,这两个参数都是函数类型
我们可以用.then来指定成功或失败的回调。(第一个回调是成功的回调,参数为调用resolve时传过来的参数,第二个回调是失败的回调,参数为调用reject传过来的参数)

p.then((res)=>{
   
    console.log('异步成功:',res);  //异步成功:12
},(error)=> {
   
    console.log('异步失败:',error);  //异步失败:66
})

下面这个用catch写法和上面是等价的:

p.then((res)=>{
   
    console.log('异步成功:',res); //异步成功:12
}).catch((error)=> {
   
    console.log('异步失败:',error);  //异步失败:66
})

1.使用Promise封装原生AJAX

//定义一个方法,发送ajax请求
function sendAjax() {
   
    return new Promise((resolve, reject) => {
   
        const xhr = new XMLHttpRequest();
        xhr.responseType = 'json';  //指定返回结果格式
        xhr.open('GET', 'https://ku.qingnian8.com/dataApi/news/navlist.php');
        xhr.send();
        xhr.onreadystatechange = () => {
   
            if (xhr.readyState === 4) {
   
                if (xhr.status >= 200 && xhr.status < 300) {
   
                    resolve(xhr.response);
                } else {
   
                    reject(xhr.status);
                }
            }
        }
    });
}

//调用方法返回的是promise对象,直接.then就欧了
sendAjax().then(res => {
   
    console.log(res);
}).catch(err => {
   
    console.log(err);
})

2.Promise实例对象的两个属性

回到前边的抽奖案例,如果我们打印一下p,可以看到两个属性:

在这里插入图片描述

上面是成功,下面是失败

在这里插入图片描述
是的,这两个属性分别是状态属性PromiseState和结果值属性PromiseResult

(1)状态属性PromiseState

有三个值,分别是pendingfulfilledrejected
promise状态的改变只有两种,分别是:

1、pending => fulfilled
2、pending => rejected

而且一个promise对象只会改变一次,改变之后就不会再变

(2)结果值属性PromiseResult

这个属性保存的是异步成功或失败的结果
无论成功还是失败,都只有一个结果数据
这个结果是通过resolvereject这两个函数参数,保存在PromiseResult属性中的
成功穿过去的参数一般叫value,失败的参数一般叫reason(当然我习惯写res和err)

3.Promise的工作流程

在这里插入图片描述

4.Promise的API

Promise对象中的函数是同步调用的,下面的代码依次输出:我同步执行,奥里给

const p = new Promise((resolve, reject) => {
   
	//这个函数是同步调用的
	console.log('我同步执行');
});
console.log('奥里给');

(1).then和.catch

这部分上面讲过了,可以去看看0.初体验部分

(2)Promise.resolve(参数)

这个方法可以返回一个Promise对象,注意:

1、如果传入的参数是一个非Promise类型,那么返回一个成功的Promise对象,参数也就是成功的回调中的value值

const p1 = Promise.resolve(521);
console.log(p1);

在这里插入图片描述

2、如果传入的参数是一个Promise类型,那么返回的结果取决于传入的Promise的结果
如果结果为resolve,那么返回成功的Promise,值就是里面调用resolve的参数成功

const p2 = Promise.resolve(new Promise((resolve,reject) => {
   
    resolve('成功');
}))
console.log(p2);

在这里插入图片描述

3、如果结果为reject,那么返回失败的Promise,值就是里面调用reject的参数失败

const p2 = Promise.resolve(new Promise((resolve,reject) => {
   
    // resolve('成功');
    reject('失败');
}))
console.log(p2);

在这里插入图片描述

不想让控制台报错,只需要用catch捕获一下:

const p2 = Promise.resolve(new Promise((resolve,reject) => {
   
    // resolve('成功');
    reject('失败');
}))
console.log(p2);
p2.catch(err => console.log(err));

在这里插入图片描述

(3)Promise.reject(参数)

不管传入的参数是什么,都会返回一个失败的Promise对象,传入的参数是什么,结果就是什么(若参数是Promise对象,那么结果值也是Promise对象)。

1、如果传的是非Promise,返回的是失败的Promise,结果就是传的值:

const p3 = Promise.reject(520);
console.log(p3);

在这里插入图片描述

2、如果传的是成功的Promise,返回的是失败的Promise对象,该对象的结果值PromiseResult是成功的Promise对象:

const p4 = Promise.reject(new Promise((resolve,reject)=>{
   
    resolve('OK');
    // reject('错误');
}))
console.log(p4);

在这里插入图片描述

3、如果传的是失败的Promise,返回的是失败的Promise对象,该对象的结果值PromiseResult是失败的Promise对象:

const p4 = Promise.reject(new Promise((resolve,reject)=>{
   
    // resolve('OK');
    reject('错误');
}))
console.log(p4);

在这里插入图片描述

(4)Promise.all([参数1,参数2…])

1、返回结果是一个Promise对象,该方法参数是一个Promise对象构成的数组,只有所有的Promise成功,返回的状态才是成功,值为一个成功结果值构成的数组

const p1 = new Promise((resolve,reject)=> {
   
    resolve('OK');
})
const p2 = Promise.resolve('成功');
const p3 = Promise.resolve('欧了');
const result = Promise.all([p1,p2,p3]);
console.log(result);

在这里插入图片描述

2、如果有一个失败,那么返回的Promise状态为失败,结果值为第一个失败的结果值

const p1 = new Promise((resolve,reject)=> {
   
    resolve('OK');
})
const p2 = Promise.reject('失败');
const p3 = Promise.reject('完蛋');
const result = Promise.all([p1,p2,p3]);
console.log(result);

在这里插入图片描述
这玩意儿应用场景还是蛮多的,比如同时去改数据库的两个表,两个表都改完了,再使用.then的回调提示用户修改成功。

(5)Promise.race([参数1,参数2…])

参数是多个Promise对象构成的数组,这个race本身是赛跑的意思,所以这个API的作用就是:多个异步操作,哪个先返回结果(先完成),那么调用这个API返回的就是谁。

比如下面这段代码,p1加了定时器,那么p2先返回结果,所以result返回的就是一个失败的Promise,值是p2的结果值

const p1 = new Promise((resolve,reject)=> {
   
    setTimeout(() => {
   
        resolve('OK');
    }, 1000);
})
const p2 = Promise.reject('失败');
const p3 = Promise.reject('完蛋');
const result = Promise.race([p1,p2,p3]);
console.log(result);

在这里插入图片描述

二、一些关键问题

1.改变对象状态的方式

有三种方式可以改变Promise对象的状态,分别是1.resolve函数 2.reject函数 3.抛出错误

const p = new Promise((resolve,reject)=> {
   
    //1.resolve函数
    resolve('成功'); //pending => resolved/fulfilled
    //2.reject函数
    reject('失败'); //pending => rejected
    //3.抛出错误
    throw '出问题了!';  //pending => rejected
})
console.log(p);

2.能否执行多个回调

只要Promise对象的状态改变,那么对应的回调不管有几个,都会执行

const p = new Promise((resolve,reject)=> {
   
    resolve('DJ');
})

//只要p状态改变为resolved,下面三个回调都会执行
p.then(res=>console.log(res));
p.then(res=>alert(res));
p.then(res=>console.log(res,'drop the beat'));

3.改变状态和指定回调的顺序

有两种情况:
1、若状态改变为同步,那么就是改变状态 => 指定回调 => 执行回调

const p = new Promise((resolve,reject)=> {
   
     resolve('DJ');
})
p.then(res=>console.log(res));

2、若状态改变为异步,那么就是指定回调 => 改变状态 => 执行回调

const p = new Promise((resolve,reject)=> {
   
    setTimeout(()=>{
   
        resolve('DJ');
    },1000)
})
p.then(res=>console.log(res));

记住,执行回调永远在状态改变之后,执行回调和指定回调不是一个概念。指定回调是执行then方法而不是执行then里的嘎达们

4.then/catch方法返回结果由什么决定

调用then(或catch)方法返回的还是Promise对象,返回的这个Promise的状态和结果取决于then中回调的返回值。

1、如果返回非Promise,那么结果为成功的Promise对象,值就是返回值。(这里如果不写返回值,返回的也是成功的Promise,因为不写return,返回的是undefinedundefined也是非Promise类型的数据)
2、抛出错误,那么结果为失败的Promise对象,值就是抛出的值
3、返回一个Promise对象,那么结果取决于该Promise的状态

不管p的状态是成功还是失败,后面链式调用then(或catch)返回的结果,都取决于它里面的回调,就是上面那三个情况

const p = new Promise((resolve,reject)=> {
   
    resolve('成功');
})
const result = p.then(res => {
   
    //1.返回非Promise,那么结果为成功的Promise对象,值就是返回值
    //(不写return返回undefined)
    return 521; //result结果为fulfilled、521
    //2.抛出错误,那么结果为失败的Promise对象,值就是抛出的值
    throw '出了问题';  //result结果为rejected、出了问题
    
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值