自学前端日记

第七篇:Promise的基本使用

Promise简介:

抽象:Promise是JS中进行异步编程的新方案  老的(纯回调函数)

具体:从语法上来讲 Promise是一个内置的构造函数

功能上Promise的实例对象可以封装一个异步操作并可以获得其结果

1.优势:指定回调函数的方式更加灵活

旧的:必须在启动异步任务之前指定

Promise:启动异步任务 => 返回Promise对象 => 给Promise对象绑定回调函数(甚至可以在异步任务结束后指定)

2.支持链式调用,可以解决回调地狱问题

(1):什么是回调地狱:

回调函数的嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件

(2):回调地狱的弊端:

代码不便于阅读,不便于异常的处理

(3):一个不是很优秀的解决方案:

then的链式调用

(4):终极解决方案:

async/await (底层实际上依然使用then的链式调用)

大纲:

学Promise必须弄明白

Promise基本使用

Promise配合ajax使用

【利用Promise封装ajax请求】

【改变实例对象的状态和指定回调的顺序】

【.then配合ajax的链式调用】

【中断Promise链】

【错误的穿透】

【最终的解决方案async...await】ES7的最新处理方法

---------------------------------------------------------------------------------------------------------------------------------

学Promise必须弄明白

1.了解什么是函数对象与实例对象

function Fn(){
    // 函数对象
    Fn.name='wang';
}
// 实例对象
let f1 = new Fn();

2.回调函数

由我们自己定义的但是不是我们自己调用的函数

同步回调函数:

        例如:array.forEach(element => {

   });在主线程上运行的

异步回调函数:

        例如:btn.onclick = ()=>{};setTimeout(()=>{});xhr.onreadystatechange = ()=>{};

3.捕获js中任务执行时可能出现的错误以及处理方法 try...catch...

try{
    //此处放可能出现错误的代码  一旦出现错误该任务将停止执行调用catch,并携带错误信息
   }catch(error){
      //error 为错误的原因
      console.log('出错了原因是',error)
}

function isOu(){
    let time = Date.now();
    if(time%2 === 0){
         console.log('偶数可以运行')
     }else{
            throw new Error('奇数执行出错了') 
   }   
}

//捕获当上述代码运行时可能出现的错误
try{
isOu()}catch(error){
   console.log(error)
}

Promise

语法:

//实例一个Promise对象用来操作异步函数
const p = new Promise((resolve,reject)=>{

    //这里运行异步函数 例如setTimeout
     setTimeout(()=>{
        if(){//成功判断条件
             //指定成功时携带的数据
             resolve(successData) 
      }else{
            //指定失败时携带的数据
            reject(faileData)
            }
   },2000)
        
});

//指定回调函数 接收异步函数运行的结果
p.then(
      //成功时的回调函数
     (value)=>{
            console.log('成功了',value);
    },
     //失败时的回调函数
     (reason)=>{
            console.log('失败了',reason);
    }
);

(1)Promise实例对象p有三种状态

                初始化状态  pending

                成功状态      fulfilled

                失败状态      rejected

(2)当我们新建一个Promise实例对象p时 它的状态是pending 即初始化状态

(3)Promise实例对象状态的改变方式

                pending(初始化)= > fulfilled(成功)

                pendinh (初始化   = > rejected(失败)

(4)Promise实例对象的方法

               const p =  Promise.resolve() 快速创建一个成功状态的promise对象

               const p =  Promise.reject() 快速创建一个失败状态的promise对象

          const p1 = new Promise();  

          const p2 = new Promise();  

          const p3 = new Promise(); 

          const p = Promise.all([p1,p2,p3]);

          当 p1、p2、p3状态都成功时  p的状态才是成功

          当 p1、p2、p3状态有一个失败  则p的状态为失败且那个失败就从哪里停止运行

          const p = Promise.race([p1,p2,p3]);

          该方法只判断第一个也就是最短时间内出现的结果的状态

          

(5).then方法的说明

                const p = new Promise();

                p.then  用来指定Promise实例对象中的状态的回调函数
             


p.then(
        (value)=>{
            console.log('成功了',value);
        },
        (reason)=>{
            console.log('失败了',reason);
        }
)

                p.then可以返回 一个新的Promise对象 且状态为pending

                p.catch实际上是p.then方法的一个语法糖  专门用来指定失败的回调

Promise配合ajax使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise配合Ajax使用</title>
</head>

<body>
    <h3>Promise配合Ajax使用</h3>
    <p>--[Promise]---</p>
    <button id="btn">点击</button>
</body>

</html>
<script>

    const btn = document.getElementById('btn');

    btn.onclick = () => {
        //用户点击时实例一个Promise对象
        const p = new Promise((resolve, reject) => {
            //实例一个xhr对象用来前后端交互的
            const xhr = new XMLHttpRequest();
            //指定xhr异步回调函数用来接收数据的
            xhr.onreadystatechange = () => {
                if(xhr.readyState===4){
                    if(xhr.status>=200 && xhr.status<300){
                        //当异步接收数据成功时
                        resolve(xhr.response);
                    }else{
                        //当异步接收数据失败时
                        reject('我是失败的数据')
                    }
                }
            }

            xhr.responseType = 'json';

            xhr.open('GET', 'http://127.0.0.1:8080/test_promise')
            // xhr.open('GET', 'http://127.0.0.1:8080/test_promise2')//错误的地址

            xhr.send();
        });
    
        //then方法用来指定成功和失败的回调函数 目的为了接收成功失败数据
        p.then(
            (value) => {
                console.log('成功了', value);
            },
            (reason) => {
                console.log('失败了', reason);
            }
  );
}

</script>

【利用Promise封装ajax请求】

创建一个函数用来发送ajax请求 可以指定不同的  url 以及请求携带的数据

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise封装Ajax</title>
</head>

<body>
    <h3>Promise封装Ajax</h3>
    <p>--[Promise]---</p>
    <button id="btn">点击</button>
</body>

</html>
<script>

    const btn = document.getElementById('btn');

    // 创建函数 sendAjax(url,data)

    function sendAjax(url, data) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();

            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        resolve(xhr.response)
                    } else {
                        reject('失败了');
                    }
                }
            }

            xhr.responseType = 'json';

            let str = '';

            for (let key in data) {
                str += `${key}=${data[key]}&`;
            }

            xhr.open('GET', url + '?' + str.slice(0, -1));

            xhr.send();
        })
    }

    

    btn.onclick = () => {
        const p = sendAjax('http://127.0.0.1:8080/test_promise', { name: 'Cyndi' })
        p.then(
            (value) => {
                console.log('成功了',value);
            },
            (reason) => {
                console.log('失败了',reason);
            }
        )

    };

    console.log('我是主线程中的代码');
</script>

 【改变实例对象的状态和指定回调的顺序】

        1.先改变状态再指定回调:


const p = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(100)
        },1000)
    })

    setTimeout(()=>{
        p.then(
            value=>{
                
            },
            reason=>{
                
            }
        )
},3000)

        2.先指定回调再改变状态

const p = new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(100)
        },1000)
})

p.then(
        value=>{
                
          },
        reason=>{

          }
)

【.then配合ajax的链式调用】

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise的链式调用</title>
</head>

<body>
    <h3>Promise的链式调用</h3>
    <p>--[Promise]---</p>
    <button id="btn">点击</button>
</body>

</html>
<script>
    const btn = document.getElementById('btn');
    // 封装一个使用Promise处理ajax请求的函数
    function sendAjxax(url, data) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.onreadystatechange = () => {
                if(xhr.readyState===4){
                    if(xhr.status>=200 && xhr.status<300){
                        resolve(xhr.response);
                    }else{
                        reject('错误的请求');
                    }
                }
            }

            xhr.responseType = 'json';

            let str = '';
            for(let key in data){
                str += `${key}=${data[key]}&`
            }

            xhr.open('GET',url+'?'+str.slice(0,-1));

            xhr.send();
        })
    };

    btn.onclick = ()=>{
        
    sendAjxax('http://127.0.0.1:8080/test_promise1',{name:'wang'})
   .then(//命名第一次请求数据的回调
        (value)=>{
            console.log('成功了1',value);
            // 当第一次成功之后 发取第二次请求 返回一个Promise实例对象  第二次
            // 请求的结果取决于当前函数的调用结果
            return sendAjxax('http://127.0.0.1:8080/test_promise2',{name:'胡歌'});
        },
        (reason)=>{
            console.log('失败了',reason);
        }
    )
   .then(//命名第二次请求数据的回调
        (value)=>{//如果成功则获取第二次请求的数据
            console.log('成功了2',value);
            return sendAjxax('http://127.0.0.1:8080/test_promise3',{name:'Cyndi'});
        },
        (reason)=>{
            console.log('失败了',reason);
        }
    )
   .then(//命名第三次请求数据的回调
        (value)=>{//如果成功则获取第三次请求的数据
            console.log('成功了3',value);
        },
        (reason)=>{
            console.log('失败了',reason);
        } 
    )
}
    


</script>

链式调用很好的解决了回调地狱问题  只要发一个请求即可在前一次p.then成功的回调函数中返回

一个封装的ajax请求函数(返回一个新的Promise实例对象决定外侧p.then新的Promise对象的状态)

 p.then(
        value => {
            console.log(valkue);
            return sendAjax(url, data);//返回一个Promise实例对象
        },
        reason => {

        }
)//生成一个新得为初始化状态的Promise实例对象
.then(
        value => {
            console.log(valkue);
            return sendAjax(url, data)
        },
        reason => {

        }
)

【中断Promise链】

该操作目的是为了当Promise链进入到错误的状态时不会出现意外的执行(当出现请求错误的时候不停止运行,却运行了成功的回调)

原因:这个与Promise对象的自身机制是相关的

当某一次请求出错的时候就会进入到.then的错误回调中

如果错误的回调没有指定返回的结果则默认 为undefined 它是一个非promise的值  如果一个Promise实例对象的状态接收的是一个非Promise的值 则认为是成功的状态 那么下个.then就会走成功的回调  这样就不符合预期的情况 (一旦出错即停止运行)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>中断Promise链</title>
</head>

<body>
    <h3>中断Promise链</h3>
    <p>--[Promise]---</p>
    <button id="btn">点击</button>
</body>

</html>
<script>
    const btn = document.getElementById('btn');
    // 封装一个使用Promise处理ajax请求的函数
    function sendAjxax(url, data) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.onreadystatechange = () => {
                if(xhr.readyState===4){
                    if(xhr.status>=200 && xhr.status<300){
                        resolve(xhr.response);
                    }else{
                        reject('错误的请求');
                    }
                }
            }

            xhr.responseType = 'json';

            let str = '';
            for(let key in data){
                str += `${key}=${data[key]}&`
            }

            xhr.open('GET',url+'?'+str.slice(0,-1));

            xhr.send();
        })
    };

    btn.onclick = ()=>{
        
//    sendAjxax('http://127.0.0.1:8080/test_promise1',{name:'wang'})

    // 测试一下第一次请求失败是否能中端后面的任务   
   sendAjxax('http://127.0.0.1:8080/test1_promise1',{name:'wang'})
   .then(//命名第一次请求数据的回调
        (value)=>{
            console.log('第一次成功了1',value);
            // 当第一次成功之后 发取第二次请求 返回一个Promise实例对象  第二次
            // 请求的结果取决于当前函数的调用结果
            return sendAjxax('http://127.0.0.1:8080/test_promise2',{name:'胡歌'});
        },
        (reason)=>{
            console.log('第一次失败了',reason);
            // 当第一次失败的时候想要停止后面的任务 
            // 只能返回一个Promise实例状态为pending 的对象
            return new Promise(()=>{});
        }
    )
   .then(//命名第二次请求数据的回调
        (value)=>{//如果成功则获取第二次请求的数据
            console.log('成功了2',value);
            return sendAjxax('http://127.0.0.1:8080/test_promise3',{name:'Cyndi'});
        },
        (reason)=>{
            console.log('第二次失败了',reason);
            return new Promise(()=>{});
        }
    )
   .then(//命名第三次请求数据的回调
        (value)=>{//如果成功则获取第三次请求的数据
            console.log('成功了3',value);
        },
        (reason)=>{
            console.log('第三次失败了',reason);
            return new Promise(()=>{});
        } 
    )
}
    


</script>

【错误的穿透】

目的是为了简化上述中断Promise链太繁杂的处理方式

其实就是不指定错误的回调 而在最后面添加一个.catch方法用来处理当执行错误的时候执行的函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>错误的穿透</title>
</head>

<body>
    <h3>错误的穿透</h3>
    <p>--[Promise]---</p>
    <button id="btn">点击</button>
</body>

</html>
<script>
    const btn = document.getElementById('btn');
    // 封装一个使用Promise处理ajax请求的函数
    function sendAjxax(url, data,index) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.onreadystatechange = () => {
                if(xhr.readyState===4){
                    if(xhr.status>=200 && xhr.status<300){
                        resolve(xhr.response);
                    }else{
                        reject(`第${index}次失败了`);
                    }
                }
            }

            xhr.responseType = 'json';

            let str = '';
            for(let key in data){
                str += `${key}=${data[key]}&`
            }

            xhr.open('GET',url+'?'+str.slice(0,-1));

            xhr.send();
        })
    };

    btn.onclick = ()=>{
    
        
    //第一次成功的请求
    sendAjxax('http://127.0.0.1:8080/test_promise1',{name:'wang'})

    // 测试一下第一次请求失败是否能中端后面的任务   
    // sendAjxax('http://127.0.0.1:8080/test1_promise1',{name:'wang'},1)
   .then(//命名第一次请求数据的回调
        (value)=>{
            console.log('第一次成功了1',value);
            // 当第一次成功之后 发取第二次请求 返回一个Promise实例对象  第二次
            // 请求的结果取决于当前函数的调用结果
            return sendAjxax('http://127.0.0.1:8080/test_promise2',{name:'胡歌'},2);
        }
    )
   .then(//命名第二次请求数据的回调
        (value)=>{//如果成功则获取第二次请求的数据
            console.log('第二次成功了',value);
            return sendAjxax('http://127.0.0.1:8080/test_promise3',{name:'Cyndi'},3);
        }
  
    )
   .then(//命名第三次请求数据的回调
        (value)=>{//如果成功则获取第三次请求的数据
            console.log('第三次成功了',value);
        }
        
    )
    .catch(
        reason =>{
            console.log('失败了',reason);
        }
    )
}
    


</script>

【最终的解决方案async...await】ES7的最新处理方法

        1.async修饰的函数
             函数的返回值为Promise对象
             Promise实例的结果有async函数执行的返回值决定
             
        2.await表达式
             await右侧的表达式,一般为Promise实例对象,但也可以是其他的值
             如果表达式是Promise对象,await后的返回值是Promise成功的值
             如果表达式是其他值,直接将此值作为await的返回值

        3.注意:
            await必须写在async函数中,但async函数中可以没有await
            如果await的Promise的值失败了,就会抛出异常,需要通过try...catch来捕获异常

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>async&await的应用规则</title>
</head>

<body>
    <h3>async&await的应用</h3>
    <p>--[async&await]---</p>
    <button id="btn">点击</button>
</body>

</html>
<script src="../jquery.min.js"></script>
<script>
    const btn = document.getElementById('btn')
   function sendAjxax(url, data) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.onreadystatechange = () => {
                if(xhr.readyState===4){
                    if(xhr.status>=200 && xhr.status<300){
                        resolve(xhr.response);
                    }else{
                        reject('出错了');
                    }
                }
            }

            xhr.responseType = 'json';

            let str = '';
            for(let key in data){
                str += `${key}=${data[key]}&`
            }

            xhr.open('GET',url+'?'+str.slice(0,-1));

            xhr.send();
        })
    };


   btn.onclick = ()=>{
    ;(async()=>{
       try{
        const res1 = await sendAjxax('http://127.0.0.1:8080/test_promise1',{name:'wang'});
        console.log(res1);
        const res2 = await sendAjxax('http://127.0.0.1:8080/test_promise2',{name:'hu'});
        console.log(res2);
        const res3 = await sendAjxax('http://127.0.0.1:8080/test_promise3',{name:'Cyndi'});
        console.log(res3);
       }catch(error){
            console.log('出错了',error);
       }
    })();
   }


</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值