Promise

Promise

Promise还是什么?

理解

  1. 抽象表达:

    1)Promise是一门新的技术(ES6规范)

    2)Promise是JS中进行异步编程的新解决方案

    备注:就方案是单纯使用回调函数

  2. 具体表达:

    1)从语法上来说:Promise是一个构造函数

    2)从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

  3. 异步编程

    • fs文件操作

      require('fs').readFile('./index.html', (err,data)=>{})
      
    • 数据库操作

    • AJAX

      $.get('/server',(data)=>{})
      
    • 定时器

      setTimeout(()=>{},2000);
      

promise的状态改变

状态是实例对象中的一个属性 PromiseState

有三个值:

  • pending 未决定的

  • resolved / fullfilled 成功

  • rejected 失败

状态只有两种变化方式

  1. pending变为resolved
  2. pending变为rejected

说明:只有这两种,且一个promise对象只能改变一次

无论变为成功还是失败,都会有一个结果数据

成功的结果数据一般称为value,失败的结果数据一般称为reason

Promise对象的值

实例对象中的另一个属性 PromiseResult

保存着对象(异步任务)的成功失败的结果

  • resolve
  • reject

promise的基本流程

const p=new Promise((resolve,reject)=>{
	//执行异步操作
	//成功调用resolve(),将promise状态设置为成功 resolved
	resolve(data)//可以传参数
	//失败调用reject(),将promise状态设置为失败 rejected
	reject(data)//可以传参数
});

/*调用then方法来定义resolve函数和reject函数分别要做什么,上面是resolve函数的定义,默认形参名为value,下面是reject函数的定义,默认形参名为reason。*/

p.then(value=>{
	//成功回调 onResolved() 返回一个新的Promise对象
},reason=>{
	//失败回调 onRejected()	返回一个新的Promise对象
})

使用示例
1-promise初体验.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>抽奖</title>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <h2 class="page-header">Promise初体验</h2>
        <button class="btn btn-primary" id="btn">点击抽奖</button>
    </div>

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

        /**
         * 点击按钮,2s后显示是否中奖(30%概率中奖)
         * 若中奖弹出 恭喜,奖品为10w
         * 若未中奖弹出 再接再厉
         * 
         */

        //获取元素对象
        const btn=document.querySelector('#btn');
        //绑定单击事件
        btn.addEventListener('click',function(){
            //定时器
            // setTimeout(()=>{
            //     //30% 1-100 1 2 30
            //     //获取从1-100的一个随机数
            //     let n=rand(1,100);
            //     //判断
            //     if(n<=30){
            //         alert('恭喜,奖品为10w');
            //     }else{
            //         alert('再接再厉');
            //     }
            // },1000);

            //Promise形式实现
            //resolve 解决 函数类型的数据
            //reject 拒绝 函数类型的数据
            const p=new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    //30% 1-100 1 2 30
                    //获取从1-100的一个随机数
                    let n=rand(1,100);
                    //判断
                    if(n<=30){
                        resolve(n);//将promise对象的状态设置为 成功
                    }else{
                        reject(n);//将promise对象的状态设置为 失败
                    }
                },1000);
            });

            //调用then方法
            p.then((value)=>{
                alert('恭喜,奖品为10w,您的中奖数字为 '+value);
            },(reason)=>{
                alert('再接再厉,您的号码为 '+reason);
            })
        })

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

2-promise实践练习.js

const { rejects } = require('assert');
const fs=require('fs');
const { resolve } = require('path');

//回调函数 形式
// fs.readFile('./resource/content.txt',(err,data)=>{
//     //如果出错,则抛出错误
//     if(err) throw err;
//     //输出文件内容
//     console.log(data.toString());
// })

//promise形式
let p=new Promise((resolve,reject)=>{
    fs.readFile('./resource/content.txt',(err,data)=>{
        //如果出错,则抛出错误
        if(err) reject(err);
        //输出文件内容
        resolve(data);
    });
});

//调用then
p.then(value=>{
    console.log(value.toString());
},reason=>{
    throw(reason)
})

3-promise实践练习-AJAX请求.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise 封装 AJAX</title>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <h2 class="page-header">Promise 封装AJAX操作</h2>
        <button class="btn btn-primary" id="btn">点击发送AJAX</button>
    </div>
    <script>
        //接口地址 https://api/apiopen.top/getJoke  不能用
        //获取元素对象
        const btn=document.querySelector('#btn')

        btn.addEventListener('click',function () { 
            //创建promise
            const p=new Promise((resolve,reject)=>{
                //1.创建对象
                const xhr=new XMLHttpRequest()
                //2.初始化
                xhr.open('GET','https://randomuser.me/api/');
                //3.发送
                xhr.send();
                //4.处理响应结果
                xhr.onreadystatechange=function(){
                    if(xhr.readyState===4){
                        //判断响应状态码 2xx
                        if(xhr.status>=200 && xhr.status<300){
                            resolve(xhr.response);
                        }else{
                            reject(xhr.status);
                        }
                    }
                }
            });
            
            p.then(value=>{
                //控制台打印响应结果
                console.log(JSON.parse(value));
            },reason=>{
                //控制台打印响应状态码
                console.warn(reason);
            })
         })
    </script>
</body>
</html>

4-promise封装练习-fs模块.js

/** 
 * 封装一个函数mineReadFile读取文件内容
 * 参数:path文件路径
 * 返回promise对象
 */

const { rejects } = require("assert");
const { resolve } = require("path");

function mineReadFile(path){
    return new Promise((resolve,reject)=>{
        //读取文件
        require('fs').readFile(path,(err,data)=>{
            //判断
            if(err) reject(err);
            //成功
            resolve(data);
        })
    })
}

mineReadFile('./resource/content.txt')
.then(value=>{
    //输出文件内容
    console.log(value.toString());
},reason=>{
    console.log(reason);
})

5-util.promisify方法.js (将原来的方法进行promise风格转化)

//util.promisify方法

//引入util模块
const util=require('util');
//引入fs模块
const fs=require('fs');
//返回一个新的函数
let mineReadFile=util.promisify(fs.readFile);

mineReadFile('./resource/content.txt')
.then(value=>{
    console.log(value.toString());
})

6-promise封装练习.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise封装AJAX操作</title>
</head>
<body>
    <script>
        /**
         * 封装一个函数sendAJAX发送GET AJAX请求
         * 参数  URL
         * 返回结果 Promise对象
         * */
        function sendAJAX(url){
            return new Promise((resolve,reject)=>{
                const xhr=new XMLHttpRequest();
                xhr.responseType='json';
                xhr.open('GET',url);
                xhr.send();
                //处理结果
                xhr.onreadystatechange=function(){
                    if(xhr.readyState===4){
                        //判断成功
                        if(xhr.status>=200 && xhr.status<300){
                            //成功的结果
                            resolve(xhr.response);
                        }else{
                            //失败的结果
                            reject(xhr.status);
                        }
                    }
                }
            })
        }

        sendAJAX('https://randomuser.me/api/')
        .then(value=>{
            console.log(value);
        },reason=>{
            console.log(reason);
        })
    </script>
</body>
</html>

为什么要用Promise?

指定回调函数的方式更加灵活

  1. 旧的:必须在启动异步任务前指定
  2. promise:启动异步任务=>返回promise对象=>给promise对象绑定回调函数(甚至可以在异步任务结束后指定多个成功或失败的结果)

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

  1. 什么是回调地狱?

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

  2. 回调地狱的缺点?

    不便于阅读

    不便于异常处理

  3. 解决方案?

    promise链式调用

如何使用Promise?

API

  1. Promise沟槽函数:Promise(executor){}

    (1) executor函数:执行器 (resolve,reject)=>{}

    (2) resolve函数:内部定义成功时我们调用的函数 value=>{}

    (3) reject函数:内部定义失败时我们调用的函数 reson=>{}

    说明:executor会在Promise内部立即同步调用,异步操作在执行器中执行,就是随着Promise对象的创建执行器操作也立即被执行了

  2. Promise.prototype.then 方法:(onResolved,onRejected)=>{}

    (1) onResolved函数:成功回调函数 (value)=>{}

    (2) onRejected函数:失败回调函数 (reason)=>{}

    说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象

  3. Promise.prototype.catch方法(只能回调失败函数):(onRejected)=>{}

    (1) onRejected函数:失败的回调函数 (reason)=>{}

    let p=new Promise((resolve,reject)=>{
                //修改promise状态
                reject('error')
            })
    
            //执行catch方法
            p.catch(reason=>{
                console.log(reason);
            })
    
  4. Promise.resolve 方法:(value)=>{}

    (1) value:成功的数据或promise对象

    说明:返回一个成功/失败的promise对象

     let p1=Promise.resolve(5221);
            console.log(p1);
            //如果传入的参数为 非Promise类型的对象,则返回的结果为成功promise对象
            //如果传入的参数为 Promise对象,则参数的结果决定了resolve的结果
            let p2=Promise.resolve(new Promise((resolve,reject)=>{
                reject('Error')
                // resolve('OK');
            }))
    
            p2.catch(reason=>{
                console.log(reason);
            })
            console.log(p2);
    
  5. Promise.reject 方法:(reason)=>{}

    (1) reason:失败的原因

    说明:返回一个失败的promise对象,不管传入的参数是什么类型,都是返回传入的数据或对象的失败结果,即使传入的是一个成功的promise对象。

  6. Promise.all方法:(promises)=>{}

    (1) promises:包含n个promise的数组

    说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败,成功的返回结果是所有成功promise的结果组成的数组,失败返回的是失败的那个promise的结果。

    注意:

    Promise.all 中,只要有一个 Promise 失败(即变为 rejected 状态),整个 Promise.all 调用就会立即失败,并返回第一个被拒绝的 Promise 的拒绝原因。其他 Promise 的状态不再被关注。

    全成功:

    let p1=new Promise((resolve,reject)=>{
                resolve('OK');
            })
            let p2=Promise.resolve('Success')
            let p3=Promise.resolve('OKKKKK')
    
            const result=Promise.all([p1,p2,p3]);
    
            console.log(result);
    

    p3失败:失败结果值为p3结果值

    let p1=new Promise((resolve,reject)=>{
                resolve('OK');
            })
            let p2=Promise.resolve('Success')
            let p3=Promise.reject('OKKKKK')
    
            const result=Promise.all([p1,p2,p3]);
    
            console.log(result);
    
  7. Promise.race 方法:(promises)=>{}

    (1) promises:包含n个promise的数组

    说明:返回一个新的promise,第一个完成的promise结果状态就是最终的结果状态

promise的几个关键问题

  1. 如何改变promise的状态?

    (1)resolve(value): 如果当前是pending就会变为resolved

    (2)reject(reason): 如果当前是pending就会变为rejected

    (3)抛出异常:如果当前是pending就会变为rejected

    let p=new Promise((resolve,reject)=>{
                //1.resolve函数
                resolve('ok'); //pending => fulfilled(resolved)
                //2.reject函数
                reject('error'); //pending => rejected
                //3.抛出错误
                throw '出问题了'
            })
    
            console.log(p);
    
  2. 一个promise指定多个成功/失败回调函数,都会调用吗?

    当promise改变为对应状态时都会调用

    let p=new Promise((resolve,reject)=>{
                resolve('ok');
            });
    
            //指定回调1
            p.then(value=>{
                console.log(value);
            });
    
            //指定回调2
            p.then(value=>{
                alert(value);
            })
    
  3. 改变promise状态和指定回调函数谁先谁后?

    (1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调

    (2)如何先改状态再指定回调?

    • 在执行器中直接调用resolve()/reject()
    • 延迟更长时间才调用then()

    (3)什么时候才能得到数据?

    • 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
    • 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
  4. promise.then()返回的新promise的结果状态由什么决定

    promise.then() 返回的新 Promise 的结果状态由 then 方法的回调函数(onResolvedonRejected)的执行结果决定。具体来说:

    1. 如果 onResolvedonRejected 返回一个值,新的 Promise 将会被 resolve 成这个值。
    2. 如果 onResolvedonRejected 抛出一个错误,新的 Promise 将会被 reject,并且 reject 原因是这个错误。
    3. 如果 onResolvedonRejected 返回一个 Promise,新的 Promise 将会采用这个 Promise 的状态(resolvedrejected),并且相应地 resolvereject
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值