ES6之Promise

Promise是异步操作的一种解决方案

// 1.认识Promise
    document.addEventListener('click',()=>{
        console.log('这里是异步的');
    });
    console.log('这里是同步的');

Promise一般用来解决层层嵌套的回调函数(回调地狱)的问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        #box{
            width: 300px;
            height: 300px;
            background-color: red;
            transition: all .5s;
        }
    </style>
</head>
<body>
<div id="box"></div>
<script>
    // 运动
    const move=(el,{x=0,y=0}={},end=()=>{})=>{
        el.style.transform=`translate3d(${x}px,${y}px,0`;
        el.addEventListener('transitionend',()=>{
            end();
        });
    };

    const boxEl=document.getElementById('box');
    document.addEventListener('click',()=>{
        move(boxEl,{x:150},()=>{
            move(boxEl,{x:150,y:150},()=>{
                move(boxEl,{y:150},()=>{
                    move(boxEl,{x:0,y:0});
                })
            })
        })
    });
</script>
</body>
</html>

Promise的基本用法

  • 实例化构造函数生成实例对象
  • Promise的状态
// 1.实例化构造函数生成实例对象
    console.log(Promise);

    // Promise解决的不是回调函数,而是回调地狱
    //const p=new Promise(()=>{});

    // 2.Promise的状态
    const p=new Promise((resolve,reject)=>{

    });
    console.log(p);

  

Promise有3种状态,一开始是pending(未完成),执行resolve,变成fulfilled(resolved),已成功,执行reject,变成rejected,已失败

// 2.Promise的状态
    const p=new Promise((resolve,reject)=>{
        resolve();
    });
    console.log(p);

// 2.Promise的状态
    const p=new Promise((resolve,reject)=>{
        // resolve();
        reject();
    });
    console.log(p);

  

Promise的状态一旦发生变化,就不会再变化了 eg:先调用resolve()再调用reject() 状态从pending->fulfilled 之后虽然执行了reject(),但是状态不变还是fulfilled

// 2.Promise的状态
    const p=new Promise((resolve,reject)=>{
        resolve();
        reject();
    });
    console.log(p);

 

  • then方法
// 2.Promise的状态
    const p=new Promise((resolve,reject)=>{
        resolve();
    });

    // 3.then()方法
    // 第一个回调函数代表成功 第二个回调函数代表失败
    p.then(()=>{
        console.log('success');
    },()=>{
        console.log('error');
    });

控制台输出success,如果调用reject()方法,则输出error 

  • resolve和reject函数的参数
// 2.Promise的状态
    const p=new Promise((resolve,reject)=>{
        resolve({username:'jessica'});
        //reject(new Error('reason'));
    });

    // 3.then()方法
    // 第一个回调函数代表成功 第二个回调函数代表失败
    // 4.resolve()和reject()参数
    p.then((data)=>{
        console.log('success',data);
    },(err)=>{
        console.log('error',err);
    });

Promise的实例方法

then()返回的是一个新的Promise对象 

  • 什么时候执行
  • 执行后的返回值
  • then方法返回的Promise对象的状态改变(return后面的东西会用Promise包装一下
const p=new Promise((resolve,reject)=>{
        // 第一次调用resolve方法必须写 后面新的Promise对象可不写 
        resolve();
    });
    p.then(()=>{
        console.log('success1');
        // 默认返回的是 undefined
        // 默认返回的是成功状态的Promise对象
        // 不传参数的话可以不写return语句 最方便
        // return undefined;
        // 传参数的话直接return+参数 方便
        // return 123;
        // 也可以用下面的形式 源代码就是这样
        return new Promise((resolve,reject)=>{
            // resolve(undefined);
            // resolve(123);
            reject('reason');
        })
    },()=>{
        console.log('error1');
    }).then(data=>{
        console.log('success2',data);
    },err=>{
        console.log('error2',err);
    })

 

  • 向后传值
  • 使用Promise解决回调地狱
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #box {
            width: 300px;
            height: 300px;
            background-color: red;
            transition: all .5s;
        }
    </style>
</head>
<body>
<div id="box"></div>
<script>
    // 运动
    const move = (el, {x = 0, y = 0} = {}, end = () => {
    }) => {
        el.style.transform = `translate3d(${x}px,${y}px,0`;
        el.addEventListener('transitionend', () => {
            end();
        });
    };

    const boxEl = document.getElementById('box');
    const movePromise = (el, point) => {
        return new Promise(resolve => {
            move(el, point, () => {
                resolve();
            });
        });
    };

    document.addEventListener('click', () => {
        movePromise(boxEl, {x: 150})
            .then(() => {
                return movePromise(boxEl, {
                    x: 150, y: 150
                });
            })
            .then(() => {
                return movePromise(boxEl, {
                    y: 150
                });
            })
            .then(() => {
                return movePromise(boxEl, {x: 0, y: 0});
            });
    }, false);
</script>
</body>
</html>

 

catch()方法专门用来处理rejected状态 

catch()可以捕获它前面的错误,一般总是建议,Promise对象后面要跟catch方法,这样可以处理Promise内部发生的错误

const p=new Promise((resolve,reject)=>{
        //resolve();
        reject('reason');
    });
    // 第一个then只有一个箭头函数,但是由于上面是失败状态
    // 只能通过下一次then继续寻找第二个箭头函数,如若找不到以此类推寻找
    // p.then(data=>{
    //     console.log(data);
    // }).then(null,err=>{
    //     console.log(err);
    // });

    // catch是then的特例
    // 专门捕获失败时状态
    p.then(data=>{
        console.log(data);
    }).catch(err=>{
        console.log(err);
        //默认返回undefined,成功状态的Promise对象
        // 可以制造出失败时错误
        throw new Error('reason');
    }).then(data=>{
        console.log(data);
    })

finally()方法

  • 什么时候执行
  • 当Promise状态发生变化时,不论如何变化都会执行,不变化不执行
// finally一般不接收参数
    new Promise((resolve,reject)=>{
        // resolve(123);
        reject('reason');
    }).finally(data=>{
        console.log(data);
    }).catch(err=>{
        console.log(err);
    })

 

构造函数方法

Promise.resolve()和Promise.reject()

当Promise.resolve()的参数接收的是Promise对象时,那么直接返回Promise对象,什么都不做

const p1=new Promise(resolve => {
        setTimeout(resolve,1000,'我执行了');
        // 定时器第三个参数相当于以下这种形式
        setTimeout(()=>{
            resolve('我执行了')
        },1000);
    });

    // 当Promise.resolve()接收的是Promise对象时,
    // 直接返回这个Promise对象,什么都不做
    Promise.resolve(p1).then(data=>{
        console.log(data);
    })
    // 等价于
    // p1.then(data=>{
    //     console.log(data);
    // })
    console.log(Promise.resolve(p1) === p1);//true

 控制台隔了1s后才输出我执行了

当resolve函数接收的是Promise对象时,后面的then会根据传递的Promise对象的状态变化决定执行哪一个回调

const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
        // 定时器第三个参数相当于以下这种形式
        setTimeout(() => {
            resolve('我执行了')
        }, 1000);
    });

    new Promise(resolve => resolve(p1)).then(data=>{
        console.log(data);
    })

当resolve函数接收的是具有then()方法的对象时

const thenable={
        then(){
            console.log('then');
        }
    };
    Promise.resolve(thenable).then(
        data=>console.log(data),
        err=>console.log(err));
    console.log(Promise.resolve(thenable));

pending状态,所以回调一个都不会执行

要执行回调,需要以下操作

const thenable={
        then(resolve,reject){
            console.log('then');
            resolve('resolve');
        }
    };
    Promise.resolve(thenable).then(
        data=>console.log(data),
        err=>console.log(err));
    console.log(Promise.resolve(thenable));

 

reject函数:不管什么参数,都会原封不动地向后传递作为后续方法的参数

const p1 = new Promise(resolve => {
        setTimeout(resolve, 1000, '我执行了');
        // 定时器第三个参数相当于以下这种形式
        // setTimeout(() => {
        //     resolve('我执行了')
        // }, 1000);
    });

    // new Promise((resolve,reject)=>{
    //     reject('reason');
    // })
    // // 简写形式
    // Promise.reject('reason');

    Promise.reject(p1).catch(
        err => console.log(err)
    )

 

 Promise.all()

  • 关注多个Promise对象的状态变化 传入多个Promise实例,包装成一个新的Promise实例返回
  • Promise.all()的状态变化与所有传入的Promise实例对象状态有关
  • 所有状态都变成resolved,最终的状态才会变成resolved
  • 只要有一个变成rejected,最终的状态就变成rejected
const delay=ms=>{
        return new Promise(resolve => {
            setTimeout(resolve,ms);
        })
    };
    const p1=delay(1000).then(()=>{
        console.log('p1 完成了');
        return 'p1';
    });
    const p2=delay(2000).then(()=>{
        console.log('p2 完成了');
        return 'p2';
        // return Promise.reject('reason');
    });
    const p=Promise.all([p1,p2]);
    p.then(data=>{
        console.log(data);
    },err=>{
        console.log(err);
    })

Promise.race():竞赛永争第一

  • Promise.race()的状态取决于第一个完成的Promise实例对象,如果第一个完成的成功了,那最终就成功;如果第一个完成的失败了,那最终就失败
const delay=ms=>{
        return new Promise(resolve => {
            setTimeout(resolve,ms);
        })
    };
    const p1=delay(1000).then(()=>{
        console.log('p1 完成了');
        // return 'p1';
        return Promise.reject('reason');
    });
    const p2=delay(2000).then(()=>{
        console.log('p2 完成了');
        return 'p2';
    });
    const racePromise=Promise.race([p1,p2]);
    racePromise.then(data=>{
        console.log(data);
    },err=>{
        console.log(err);
    })

 

Promise.allSettled()

  • Promise.allSettled()的状态与传入的Promise状态无关,永远都是成功的
const delay=ms=>{
        return new Promise(resolve => {
            setTimeout(resolve,ms);
        })
    };
    const p1=delay(1000).then(()=>{
        console.log('p1 完成了');
        return 'p1';
        //return Promise.reject('reason');
    });
    const p2=delay(2000).then(()=>{
        console.log('p2 完成了');
        return 'p2';
    });
    const allSettledPromise=Promise.allSettled([p1,p2]);
    allSettledPromise.then(data=>{
        console.log(data);
    });

 

Promise的注意事项

  • resolve或reject函数执行后的代码(推荐在调用其函数时加上return,不再执行它们后面的代码)
  • Promise.all/race/allSettled的参数问题
  • 参数如果不是Promise数组,会将不是Promise的数组元素转变成Promise对象
Promise.all([1,2,3]).then(datas=>{
        console.log(datas);
    })
    // 相当于
    Promise.all([
        Promise.resolve(1),
        Promise.resolve(2),
        Promise.resolve(3)]
    ).then(datas=>{
        console.log(datas);
    })

 

  • 不只是数组,任何可遍历的都可以作为参数(数组、字符串、Set、Map、NodeList、arguments)
Promise.all(new Set([1,2,3])).then(datas=>{
        console.log(datas);
    })

 

  • Promise.all/race/allSettled的错误处理

Promise的应用

异步加载图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        #img {
            width: 80%;
            padding: 10%;
        }
    </style>
</head>
<body>
<img src="https://img.mukewang.com/5e6af63d00011da318720764.jpg" alt="" id="img" >
<script>
    // 异步加载图片
    const loadImgAsync = url => {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.onload = () => {
                resolve(img);
            }

            img.onerror = () => {
                reject(new Error(`Could not load image at ${url}`));
            }
            img.src = url;
        });
    };
    const imgDOM = document.getElementById('img');
    loadImgAsync('https://2img.mukewang.com/5f057a6a0001f4f918720764.jpg')
        .then(img => {
            console.log(img.src);
            setTimeout(() => {
                imgDOM.src = img.src;
            }, 1000);
        })
        .catch(err => {
            console.log(err);
        });

</script>
</body>
</html>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值