ES6(四)Promise的理解与使用

一、什么是Promise?

Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象(Promise对象是一个构造函数,用来生成Promise实例),从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。

Promise 不解决异步问题,解决的是异步的写法

二、语法

new Promise( function(resolve, reject) {...} /* executor */ );

let p = new Promise(function(resolve,reject){
    // 这个函数会被 Promise
    setTimeout(()=>{
        resolve("传参");// 当我们调用了 resolve 就代表该异步完成,并且成功拿到结果
    },2000);
});
p.then(function(res){
    console.log(res);//传参
});
三、参数 executor

executor是带有 resolve 和 reject 两个参数的函数 。
Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回新建对象前被调用)。
resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。
executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略

let p = new Promise(function(resolve,reject){
    let img = new Image();
    img.src = `https://timgsa.babidu.com/timg?image&quality=80&size=b9999_10000&sec=1576855691894&di=b694b104df1eb0b53ee6b52d8ad6fb49&imgtype=0&src=http%3A%2F%2Fpic.vjshi.com%2F2018-10-30%2F26b945dcada739a37b4d1fecc1d10abb%2F00004.jpg%3Fx-oss-process%3Dstyle%2Fwatermark`;
    img.onload = function(){
        resolve("图片请求成功")
    };
    img.onerror = function(){
        reject("图片请求失败");
    };
}).then((res)=>{
    console.log(res);
},(rej)=>{
    console.log(rej);
});

四、then
promise.then(onFulfilled,onRejected)

参数:

  • onFulfilled
    当Promise变成接受状态(fulfillment)时,该参数作为回调函数被调用(参考: Function)。该函数有一个参数,即接受的最终结果(the fulfillment value)。如果传入的 onFulfilled 参数类型不是函数,则会在内部被替换为(x) => x ,即原样返回 promise 最终结果的函数
  • onRejected
    当Promise变成拒绝状态(rejection )时,该参数作为回调函数被调用(参考: Function)。该函数有一个参数,,即拒绝的原因(the rejection reason)。
 new Promise(promise的回调函数,在实例化时会直接执行function(resolve,reject){
        // resolve 调用该 函数 resolve(传递给成功的执行函数的数据) 代表异步执行完成,
        并成功拿到结果
        // reject 调用该函数 reject(传递给处理失败的执行函数的数据) 代表异步执行完成,
        但是没有成功拿到结果
    }).then((成功之后传递过来的数据)=>{
        console.log("成功之后的业务处理");
    },(失败之后传递过来的数据)=>{
        console.log("失败之后的业务处理");    
    });

Promise 的then方法会返回一个新的Promise对象

五、描述

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象一个 Promise有以下几种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。
六、 链式操作的用法

Promise 的 then 方法,会给我们返回一个新的 Promise 对象
新的 Promise 对象的执行状态:

  1. 默认情况下: then 返回的是一个状态是 resolved 的 Promise 对象
  2. 当then的回调函数返回的是一个 非 Promise 对象,then 返回的是一个状态是 resolved 的 Promise 对象
  3. 当 then 的回调函数返回的是一个 Promise 对象,then 返回值,也会变成该 Promise 对象
let p = new Promise((resolve,reject)=>{
    resolve(1);
});    

let p2 = p.then((data)=>{
    console.log("resolve");
    return new Promise((resolve,reject)=>{
        //reject("1");
    });
},(data)=>{
    console.log("reject");  
});

p2.then((data)=>{
    console.log("p2的resolve");
},(data)=>{
    console.log("p2的reject");
});

基于链式操作的demo示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #box {
            position: absolute;
            left: 0;
            top: 0;
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
</head>
<body>
<div id="box"></div>    
<script>
/*
    el 元素
    attr 样式
    val 目标点
    cb 动画结束之后,要做的事情

    如果目标值 比 当前值大 ,返回一个正数,否则返回一个 负数
*/    
function move(el,attr,val){
    let now = parseFloat(getComputedStyle(el)[attr]);
    let speed = val>now?1:-1;
    return new Promise((resolve)=>{
        clearInterval(el.timer);
        el.timer = setInterval(() => {
            if(Math.abs(now - val) <= 0 ){
                clearInterval(el.timer);
                resolve();
            } else {
                now += speed;
                el.style[attr] = now + "px";
            }
        }, 16);
    }); 
}
{
    let box = document.querySelector("#box");
    function boxMove(){
        move(box,"left",200).then(()=>{
            return move(box,"top",200);
        }).then(()=>{
            return move(box,"left",0);
        }).then(()=>{
            return  move(box,"top",0);
        }).then(()=>{
            boxMove()
        });
    }
    boxMove();
}
</script>    
</body>
</html>

实际工作中promise用域接口请求的实例

new Promise((resolve)=>{
    // 请求接口拿到数据
    setTimeout(()=>{
        let data = {
            state: 200, 
            isState:"ok",
            data: {
                code: 1
            }
        }
        resolve(data);
    },100);
}).then((data)=>{
    // if(data.state == 200){

    // }
    return data.data;
}).then((data)=>{
    console.log(data);
});
七、Promise 的其他用法

1.Promise.reject

Promise.reject(reason) 返回一个状态为 Rejected 的 Promise 对象

参数:
reason 失败原因

2.Promise​.resolve

Promise.resolve(value) 返回一个状态为 resolved 的 Promise 对象

参数:value 将被Promise对象解析的参数

3.Promise​.catch

捕获前一个promise抛出的错误

new Promise((resolve,reject)=>{
    reject(1);
}).then(()=>{
    console.log(1);
    return Promise.reject() // 不需要处理异步的业务,直接返回一个 reject 状态的 Promise 对象
}).then(()=>{
    console.log(2);
}).catch((err)=>{ // 捕获 前边的 Promise 中出的错误
    console.log("出错了",err);
});

4.Promise​.all

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例,当所有Promise都成功的时候,整个Promise.all才成功

5.Promise.race

与Promise.race方法类似将多个promise包装成一个新的promise实例
但是其中有一项的状态发生改变新的实例的状态就会随着改变

let p = new Promise((resolve)=>{
    setTimeout(()=>{
        console.log(1);
        resolve();
    },10);
});
let p2 = new Promise((resolve)=>{
    setTimeout(()=>{
        console.log(2);
        resolve();
    },1000);
});
let p3 = new Promise((resolve)=>{
    setTimeout(()=>{
        console.log(3);
        resolve();
    },3000);
});
// Promise.all([p,p2,p3]).then(()=>{
//     console.log(4);
// });
Promise.race([p,p2,p3]).then(()=>{
    console.log(4);
});
八、async函数

只要函数名之前加上async关键字,就表明该函数内部有异步操作。
该异步操作应该返回一个Promise对象,前面用await关键字注明。
当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句

async函数其实是在Promise 的基础上对异步方法的改写的一个新的方案

没有使用async 的Promise,如果业务需求复杂的时候,代码看起来非常冗余

new Promise((resolve)=>{
    setTimeout(()=>{
        console.log(1);
        resolve();
    },1000);
}).then(()=>{
    return new Promise((resolve)=>{
        setTimeout(()=>{
            console.log(2);
            resolve();
        },1000);
    });
}).then(()=>{
    return new Promise((resolve)=>{
        setTimeout(()=>{
            console.log(3);
            resolve();
        },1000);
    });
}).then(()=>{
    console.log("执行完成")
});

使用async 之后,看起来会稍微好点

async function fn(){
    try{
        
        let n1 = await new Promise((resolve)=>{
            setTimeout(()=>{
                console.log(0);
                resolve(1);
            },1000);
        });
        let n2 = await new Promise((resolve)=>{
            setTimeout(()=>{
                console.log(n1);
                resolve(2);
            },1000);
        });
        let n3 = await new Promise((resolve)=>{
            setTimeout(()=>{
                console.log(n2);
                resolve(3);
            },1000);
        });
        console.log(n3);

    }catch(err){
        console.log(err);
    }
}
fn();

扩展
回调地狱

  • 封装简易运动框架
  • 最早我们处理异步消息通知,都是通过回调来处理的,但是回调多了,代码的结构就必然嵌套层级特别多,造成可读性和维护性的直线下降 - 这就是回调地狱
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值