【前端】尚硅谷Promise


【前端目录贴】

1. Promise 的理解和使用

1.1 Promise 是什么?

  • 理解
  1. 抽象表达:
    • Promise 是一门新的技术(ES6 规范)
    • Promise 是 JS 中进行异步编程的新解决方案(备注:旧方案是单纯使用回调函数)
  2. 具体表达:
    • 从语法上来说: Promise 是一个构造函数
    • 从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值

1.1.1 promise两个重要属性

在这里插入图片描述

  • promise 的状态改变(PromiseState (pending/resolved(fullfilled)/rejected 三种情况))
  1. pending 变为 resolved
  2. pending 变为 rejected
    说明: 只有这 2 种, 且一个 promise 对象只能改变一次,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason, 结果只能从pending 变为resolves或rejected;
  • promise 的结果(PromiseResult),保存着异步任务『成功/失败』的结果(自己测试打印为空,暂不清楚为啥)

1.1.2 promise 的基本流程

在这里插入图片描述

1.2 为什么要用 Promise?

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

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

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

在这里插入图片描述

回调地狱: 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
回调地狱的缺点: 不便于阅读、不便于异常处理
解决方案: promise 链式调用
终极解决方案?: async/await

1.3 如何使用Promise

1.3.1 基本编码流程

  • 基本编码流程
//普通实现方式
 $('button').on('click', function () {
        setTimeout(function () {
          result= funcationRandom(1, 9);
            if (result <= 3) {
                alert('中奖了');
             } else {
                alert('没有中奖')
            }
         },1000);
        console.log('抽奖结束')
    });
    
//promise实现方式
    $('button').on('click', function () {
        // promise实现方式
        // resolve 解决  函数类型的数据
        // reject  拒绝  函数类型的数据
        //1) 创建 promise 对象(pending 状态), 指定执行器函数
        var p=new Promise((resolve,reject)=>{
            //2) 在执行器函数中启动异步任务
            setTimeout(function () {
                result= funcationRandom(1, 9);
                /**
                 * 3) 根据结果做不同处理
                 * 3.1) 如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状
                 * 3.2) 根据结果做不同处理:如果成功了, 调用 resolve(), 指定成功的 value, 变为 resolved 状态
                 */
                if (result <= 3) {
                    resolve();  // 将 promise 对象的状态设置为 『成功』
                } else {
                    reject(); // 将 promise 对象的状态设置为 『失败』
                }
            },1000);
        });
        //调用 then 方法
        // value 值
        // reason 理由
        p.then(() => {
            alert('中奖了');
        },()=>{
            alert('没有中奖')
        })
        console.log('抽奖结束')
    });
  • 传值
$('button').on('click', function () {
        // promise实现方式
        // resolve 解决  函数类型的数据
        // reject  拒绝  函数类型的数据
        var p=new Promise((resolve,reject)=>{
            setTimeout(function () {
                result= funcationRandom(1, 9);
                if (result <= 3) {
                    resolve(result);  // 将 promise 对象的状态设置为 『成功』
                } else {
                    reject(result); // 将 promise 对象的状态设置为 『失败』
                }
            },1000);
        });
        //调用 then 方法
        // value 值
        // reason 理由
        p.then(value => {
            alert('中奖了,value='+value);
        },reason=>{
            alert('没有中奖,reason='+reason)
        })
        console.log('抽奖结束')
    });
  • fs异步
var fs = require('fs');
//回调函数形式
// fs.readFile('./aa.txt',(err,data) => {
//     if (err) {
//         throw err
//     }
//     console.log(data.toString());
// })

//promise形式
var p = new Promise((resolve, reject) => {
    fs.readFile('./aa.txt', (err, data) => {
        if (err) {
            reject(err); // 将 promise 对象的状态设置为 『失败』
        }
        resolve(data);  // 将 promise 对象的状态设置为 『成功』
    })
});
//调用 then 方法
// value 值
// reason 理由
p.then(value => {
    console.log(value.toString())
}, reason => {
    console.log(reason)
});
  • ajax异步
var p=new Promise((resolve, reject)=>{
                //1.创建对象
                var xhr = new XMLHttpRequest();
                //2.初始化 设置请求方法和url
                xhr.open('GET', 'http://127.0.0.1:3000/home');
                //3.发送
                xhr.send();
                //4.事件绑定,处理服务端返回的结果
                /**
                 * on when 当...时候
                 * readystate 是xhr对象中的属性, 表示状态0(初始化) 1(open完毕) 2(send完毕) 3(返回部分结果) 4(返回所有结果)
                 */
                xhr.onreadystatechange = function () {
                    //共改变4次,触发4次
                    //判断(服务端返回了所有的结果)
                    if (this.readyState === 4) {
                        //判断响应状态码 200 404 403 401 500
                        //2xx成功
                        if (this.status >= 200 && this.status < 300) {
                            resolve(this.response);
                        } else {
                            reject(this.status);
                        }

                    }
                }
        })
        p.then(value => {
            console.log(value)
        }, reason => {
            console.log(reason)
        });

1.3.2 util.promisify方法

将接受这种回调函数作为参数的函数,转换为返回promise的函数

//util.promisify方法: 将接受这种回调函数作为参数的函数,转换为返回promise的函数
//引入util模块
var util = require('util');
//引入fs模块
var fs = require('fs');
//返回promise版本函数
var promisify = util.promisify(fs.readFile);
promisify('./aa.txt').then((value) => {
    console.log(value.toString())
}, (reason) => {
    console.log(reason)
});

1.3.3 手动封装ajax方法

/**
     * 封装一个函数 sendAJAX 发送 GET AJAX 请求
     * 参数   URL
     * 返回结果 Promise 对象
     */
    function sendAJAX(url) {
        return new Promise((resolve, reject) => {
            //1.创建对象
            var xhr = new XMLHttpRequest();
            //2.初始化 设置请求方法和url
            xhr.open('GET', url);
            //3.发送
            xhr.send();
            //4.事件绑定,处理服务端返回的结果
            /**
             * on when 当...时候
             * readystate 是xhr对象中的属性, 表示状态0(初始化) 1(open完毕) 2(send完毕) 3(返回部分结果) 4(返回所有结果)
             */
            xhr.onreadystatechange = function () {
                //共改变4次,触发4次
                //判断(服务端返回了所有的结果)
                if (this.readyState === 4) {
                    //判断响应状态码 200 404 403 401 500
                    //2xx成功
                    if (this.status >= 200 && this.status < 300) {
                        resolve(this.response);
                    } else {
                        reject(this.status);
                    }

                }
            }
        })
    }
    sendAJAX('http://127.0.0.1:3000/server3').then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    });

1.3.4 API

  • Promise 构造函数: Promise (excutor) {}
  1. executor 函数: 执行器 (resolve, reject) => {}
  2. resolve 函数: 内部定义成功时我们调用的函数 value => {}
  3. reject 函数: 内部定义失败时我们调用的函数 reason => {}
    说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行
    var p = new Promise((resolve, reject) => {
        //同步调用
        console.log('111');
       setTimeout(function () {
           console.log('333');
           result=1;
           if (result <= 3) {
               resolve('444');  // 将 promise 对象的状态设置为 『成功』
           } else {
               reject('error'); // 将 promise 对象的状态设置为 『失败』
           }
       },500)
    });
    //异步调用
    p.then((value) => {
        console.log(value)
    },(reason)=>{
        console.log(reason)
    });
    p.catch((reason)=>{
        console.log(reason)
    })
    console.log('222');
    //依次输出111 2222 333 444 
  • Promise.prototype.then 方法: (onResolved, onRejected) => {}
  1. onResolved 函数: 成功的回调函数 (value) => {}
  2. onRejected 函数: 失败的回调函数 (reason) => {}
    说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调, 返回一个新的 promise 对象
//异步调用
    var pp=p.then((value) => {
        console.log(value)
    },(reason)=>{
        console.log(reason)
    });
    console.log(pp);//返回一个新的promise 对象
  • Promise.prototype.catch 方法: (onRejected) => {}
  1. onRejected 函数: 失败的回调函数 (reason) => {}
    说明: then()的语法糖, 相当于: then(undefined, onRejected)
 var ppp=p.catch((reason)=>{
        console.log(reason)
    })
    console.log(ppp);//返回一个新的promise 对象
  • Promise.resolve 方法: (value) => {}
  1. value: 成功的数据或 promise 对象
    说明: 返回一个成功/失败的 promise 对象 (结果是传入的值或者 传入的 promise对象的value或reason值)
/**
 * 如果传入的参数为 非Promise类型的对象 -> 则返回的结果为成功promise对象
 * 如果传入的参数为 Promise 对象 -> 则参数的结果决定了 resolve 的结果
 */
var p_resolve1=Promise.resolve(123);
    var p_resolve2=Promise.resolve(p);
    console.log(p)
    console.log(p_resolve1)
    console.log(p_resolve2)
    p_resolve2.then((value) => {
        console.log('p_resolve2'+value)
    },(reason)=>{
        console.log('p_resolve2'+reason)
    });
    console.log(p===p_resolve2)//true
  • Promise.reject 方法: (reason) => {}
  1. reason: 失败的原因
    说明: 返回一个失败的 promise 对象 (失败状态,结果是 输入的字符串值,或者promise对象)
 var p_reject1 = Promise.reject(123);
    var p_reject2 = Promise.reject(p);
    console.log(p_reject1)//失败状态,结果123
    console.log(p_reject2)//失败状态,结果是p
    p_reject1.then((value) => {
        console.log('p_reject1-then ' + value)
    }, (reason) => {
        console.log('p_reject1-then ' + reason)
    })
    p_reject2.then((value) => {
        console.log('p_reject2-then ' + value)
    }, (reason) => {
        console.log('p_reject2-then ' + reason)
    });
  • Promise.all 方法: (promises) => {}
  1. promises: 包含 n 个 promise 的数组
    说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功(结果:所有成功的promise数组), 只要有一个失败了就直接失败(结果返回失败的reason值)
var p_all1=Promise.all([p,p2]);
console.log(p_all1);
  • Promise.race 方法: (promises) => {}
  1. promises: 包含 n 个 promise 的数组
    说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态(结果是value或reason值)
var p_race=Promise.race([p,p2]);
console.log(p_race);

1.3.5 promise 的几个关键问题

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

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

  • 改变 promise 状态和指定回调函数谁先谁后?(指定和执行有差别)
  1. 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  2. 如何先改状态再指定回调?
    1. 在执行器中直接调用 resolve()/reject()
    2. 延迟更长时间才调用 then()
  3. 什么时候才能得到数据?
    1. 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
      2.如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
   var p = new Promise((resolve, reject) => {
        // resolve('ok'); // 先改状态再指定回调

        setTimeout(() => {
            resolve('OK');// 先指定回调再改状态再
        }, 3000);
    });
    console.log(p);
    p.then(value => {
            console.log(value);
    })
    // setTimeout(function () {//将then延长更长时间执行
    //     p.then(value => {
    //         console.log(value);
    //     }),5000
    // });
  • promise.then()返回的新 promise 的结果状态由什么决定?
  1. 简单表达: 由 then()指定的回调函数执行的结果决定
  2. 详细表达:
    1. 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
    2. 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value
    3. 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
    var p = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('111');// 先指定回调再改状态再
        }, 1000);
    });

    pp = p.then(value => {
        console.log(value);
        // throw 'error';//1.抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
        // return 'ok2';//2.返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('222');// 先指定回调再改状态再
            }, 1000);
        });//3.返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
    })
    console.log(p);
    console.log(pp);
  • promise 如何串连多个操作任务?
  1. promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
  2. 通过 then 的链式调用串连多个同步/异步任务
  • promise 异常传透?
  1. 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
  2. 前面任何操作出了异常, 都会传到最后失败的回调中处理
   var p = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('111');// 先指定回调再改状态再
            // reject('err');// 先指定回调再改状态再
        }, 1000);
    });

    p.then(value => {
        console.log(value);
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                // resolve('222');
                reject('err');
            }, 1000);
        });
    }).then(value => {
        console.log(value);
    }).catch(reason => {
        console.log(reason)
    })//串联(末尾也可用then)
    //.catch(value => {
    //     console.log(value);
    // },reason => {
    //     console.log(reason)
    // })
  • 中断 promise 链?
  1. 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
  2. 办法: 在回调函数中返回一个 pendding 状态的 promise 对象
 var p = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('111');// 先指定回调再改状态再
            // reject('err');// 先指定回调再改状态再
        }, 1000);
    });

    p.then(value => {
        console.log(value);
        return new Promise(() => {});//返回pending状态promise对象
    }).then(value => {
        console.log(value);
    }).catch(reason => {
        console.log(reason)
    })

1.4 手写Promise

1.5 async 与 await

1.5.1 async 函数

  1. 函数的返回值为 promise 对象
  2. promise 对象的结果由 async 函数执行的返回值决定
    (和then一样)
//then
    async function main() {
        //1. 如果返回值是一个非Promise类型的数据
        // return 521;
        //2. 如果返回的是一个Promise对象
        // return new Promise((resolve, reject) => {
        //     // resolve('OK');
        //     reject('Error');
        // });
        //3. 抛出异常
        throw "Oh NO";
    }
    let result = main();
    console.log(result)
    result.then(value => {
        console.log(value)
    },reason=>{
        console.log(reason);
    });

1.5.2 await 表达式

  1. await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
  2. 如果表达式是 promise 对象, await 返回的是 promise 成功的值
  3. 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
  4. 如果表达式是其它值, 直接将此值作为 await 的返回值
    await 必须写在 async 函数中, 但 async 函数中可以没有 await

1.5.3 async和await结合

var fs = require('fs');
//引入util模块
var util = require('util');
// //返回promise版本函数
var promisify = util.promisify(fs.readFile);

async function main() {
   try{
       data1=await promisify('./a.txt');
       data2=await promisify('./b.txt');
       data3=await promisify('./c.txt');

       console.log(data1.toString())
       console.log(data2.toString())
       console.log(data3.toString())
   }catch (e) {
       console.log(e)
   }
}
main();

1.5.4 async和await结合-ajax

/**
     * 封装一个函数 sendAJAX 发送 GET AJAX 请求
     * 参数   URL
     * 返回结果 Promise 对象
     */
    function sendAJAX(url) {
        return new Promise((resolve, reject) => {
            //1.创建对象
            var xhr = new XMLHttpRequest();
            //2.初始化 设置请求方法和url
            xhr.open('GET', url);
            //3.发送
            xhr.send();
            //4.事件绑定,处理服务端返回的结果
            /**
             * on when 当...时候
             * readystate 是xhr对象中的属性, 表示状态0(初始化) 1(open完毕) 2(send完毕) 3(返回部分结果) 4(返回所有结果)
             */
            xhr.onreadystatechange = function () {
                //共改变4次,触发4次
                //判断(服务端返回了所有的结果)
                if (this.readyState === 4) {
                    //判断响应状态码 200 404 403 401 500
                    //2xx成功
                    if (this.status >= 200 && this.status < 300) {
                        resolve(this.response);
                    } else {
                        reject(this.status);
                    }

                }
            }
        })
    }
    $('#btn').on('click', async function () {
        data=await sendAJAX('http://127.0.0.1:8000/server3');
        console.log(data);
    });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值