Promise学习笔记

目录

1. Promise介绍与基本使用

1.1 介绍

1.2 优点

1.3 基本使用

1.3.1 fs读取文件实践

1.3.2 AJAX请求实践

 1.3.3 封装fs读取文件实践

1.3.4 封装AJAX请求实践

1.3.5 util.promisify方法进行promise风格转化

1.3.6 Promise对象的状态 

1.3.7 Promise对象的值

1.3.8 Promise工作流程

2. Promise API

3. Promise关键问题

3.1 修改对象的状态 

3.2 执行多个回调 

3.3 改变状态与指定回调的顺序 

3.4 then方法返回结果 

3.5 串联多个任务 

3.6 异常穿透

3.7 中断promise链 

4. Promise自定义封装

5. async与await

5.1 async函数 

5.2 await表达式 

5.3 async与await结合实践 

5.3.1 读取文件内容

 5.3.2 发送AJAX请求


1. Promise介绍与基本使用

1.1 介绍

        Promise是JS中进行异步编程的新解决方案(旧方案是单纯使用回调函数)。Promise是一个构造函数,其对象用来封装一个异步操作并可以获取其成功/失败的结果值。

        异步编程,比如:fs文件操作、数据库操作、AJAX、定时器。

1.2 优点

        1. 支持链式调用,可以解决回调地狱问题。(回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件。不便于阅读,不便于异常处理。)

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

1.3 基本使用

// 构造一个Promise对象,封装一个异步操作
// resolve解决 reject拒绝 都是函数类型的数据
const p = new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
        let n = 1;
        if(成功){
            resolve(); // 将Promise对象的状态设置为成功
            // resolve(n);
        }else{
            reject(); // 将Promise对象的状态设置为失败
            // reject(n);
        }
    }, 1000);
});
// 调用then方法
p.then((value) => {
    // 对象状态为成功的回调
}, (reason) => {
    // 对象状态为失败的回调
});

1.3.1 fs读取文件实践

const fs = require('fs');

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

// Promise形式
let p = new Promise((resolve, reject) => {
    fs.readFile('../xxx/xxx.txt', (err, data) => {
        // 如果出错
        if(err) reject(err);
        // 如果成功
        resolve(data);
    });
});
// 调用then方法
p.then(value => {
    // 对象状态为成功的回调
    console.log(value.toString());
}, reason => {
    // 对象状态为失败的回调
    console.log(reason);
});

1.3.2 AJAX请求实践

let p = new Promise((resolve, reject) => {
    // 创建对象
    const xhr = new XMLHttpRequest();
    // 初始化设置请求方法和url
    xhr.open('GET','https://xxx/xxx');
    // 发送
    xhr.send();
    // 处理服务端返回的结果
    xhr.onreadystatechange = function(){
        //判断服务端返回了所有结果
        if(xhr.readyState === 4){
            //判断响应状态码成功
            if(xhr.status >= 200 && xhr.status < 300){
                // 输出响应体
                resolve(xhr.response);
            }else{
                // 输出状态码
                reject(xhr.status);
            }
        }
    }
});
p.then(value=>{
    // 对象状态为成功的回调
    console.log(value);
}, reason=>{
    // 对象状态为失败的回调
    console.log(reason);
});

 1.3.3 封装fs读取文件实践

// 封装一个函数mineReadFile读取文件内容
// 参数:path 文件路径
// 返回:promise 对象
function mineReadFile(path){
    return new Promise((resolve, reject) => {
        // 读取文件
        require('fs').readFile(path, (err, data) => {
            // 如果出错
            if(err) reject(err);
            // 如果成功
            resolve(data);
        }); 
    });
}
mineReadFile('../xxx/xxx.txt')
.then(value=>{
    // 输出文件内容
    console.log(value.toString());
}, reason=>{
    console.log(reason);
});

1.3.4 封装AJAX请求实践

// 封装一个函数sendAJAX发送GET请求
// 参数:URL
// 返回:Promise 对象
function sendAJAX(url){
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        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://xxx/xxx')
.then(value=>{
    console.log(value);
}, reason=>{
    console.log(reason);
});

1.3.5 util.promisify方法进行promise风格转化

        util.promisify(original);传入一个遵循常见的错误优先的回调风格的函数(即以(err, value) => {}回调作为最后一个参数),并返回一个返回promise的版本。

// 引入util模块
const util = require('util');
// 引入fs模块
const fs = require('fs');
// 返回一个新的函数
let mineReadFile = util.promisify(fs.readFile);
mineReadFile('./xxx/xxx.txt').then(value=>{
    console.log(value);
});

1.3.6 Promise对象的状态 

        实例对象中的一个属性PromiseState,共有3种值:pending(初始化未决定的)、resolved/fulfilled(成功)、rejected(失败)。共有2种状态改变:pending变为resolved、pending变为rejected。

        一个promise对象状态只能改变一次,无论哪种改变都会有一个结果数据,一般称为value(成功结果)/reason(失败结果)。

1.3.7 Promise对象的值

        实例对象中的一个属性PromiseResult,保存异步任务成功或失败的结果。resolve()和reject()可以修改这个结果。

1.3.8 Promise工作流程

2. Promise API

        1. Promise构造函数:Promise(excutor){} 

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

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

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

                说明:excutor会在Promise内部立即同步调用,异步操作在执行器中执行。

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

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

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

                说明:返回一个新的Promise对象。

        3. Promise.prototype.catch方法:(onRejected) => {}

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

                说明:返回一个新的Promise对象。

        4. Promise.resolve方法:(value) => {}

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

                说明:返回一个Promise对象。如果传入的参数为非promise对象,则返回的结果为成功

                           的promise对象。如果传入的参数为promise对象,则参数的结果决定了resolve的

                           结果。

        5. Promise.reject方法:(reason) => {}

                1)reason:失败的原因 

                说明:返回一个失败的promise对象,该对象的值为传入的参数。

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

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

                说明:返回一个新的promise。只有所有promise都成功才成功,值为所有promise成功结

                           果组成的数组。失败结果为失败promise对象的失败结果值,多个失败取第一个。

        7. Promise.race方法:(promises) => {}

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

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

3. Promise关键问题

3.1 修改对象的状态 

        1. resolve函数 pending => fulfilled(resolved)

        2. reject函数 pending => rejected

        3. 抛出问题 throw '出错了!' pending => rejected

3.2 执行多个回调 

        一个promise指定多个成功(失败)回调函数时,当promise改变为对应状态时都会调用。

3.3 改变状态与指定回调的顺序 

        1. 修改状态和.then方法谁先谁后?

            都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调。当执行

            器函数中是一个异步任务时,先指定回调再改状态,是同步任务时先改状态再指定回调。

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

            1)在执行器中直接调用resolve()/reject()

            2)延迟更长时间才调用then()

        3. 什么时候才能得到数据(回调函数什么时候执行)? 

            1)如果先改状态,then方法调用时就执行。 

            2)如果先指定回调,改变状态后执行。 

3.4 then方法返回结果 

        返回一个新的promise,新promise的结果状态由then()指定的回调函数执行的结果决定。 

        1)如果抛出异常,新promise变为rejected,reason为抛出的异常。

        2)如果返回的是非promise的任意值,新promise变为resolved,value为返回的值。

        3)如果返回的是另一个promise,此promise的结果就会成为新promise的结果。 

3.5 串联多个任务 

        promise的then()返回一个新的promise,因此可以开成then()的链式调用,串联多个同步/异步任务。

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK');
    }, 1000);
});
p.then(value => {
    return new Promise((resolve, reject) => {
        resolve("SUCCESS");
    });
}).then(value => {      // 这个then()返回的promise的状态由它指定的回调函数的返回值决定,它的回调函数没有写返回值,就是undefined,因此then()返回的promise就是一个成功的promise且返回的结果就是undefined
    console.log(value); // 打印SUCCESS
}).then(value => {
    console.log(value); // 打印undefined
})

3.6 异常穿透

        当使用promise的then链式调用时,可以在最后指定失败的回调,前面任何操作出了异常,都会传到最后失败的回调中处理。 

3.7 中断promise链 

        只有返回一个pending状态的promise对象(return new Promise(() => {});)才能中断promise链条,在中间中断,不再调用后面的回调函数。

4. Promise自定义封装

class Promise{
    // 构造方法
    constructor(executor){
        // 添加属性
        this.PromiseState = 'pending';
        this.PromiseResult = null;
        // 声明属性
        this.callbacks = [];
        // 保存实例对象的 this 的值
        const self = this;
        // resolve 函数
        function resolve(data){
            //判断状态
            if(self.PromiseState !== 'pending') return;
            // 修改对象的状态(PromiseState)
            self.PromiseState = 'fulfilled';
            // 设置对象结果值(PromiseResult)
            self.PromiseResult = data;
            // 调用成功的回调函数
            setTimeout(()=>{
                self.callbacks.forEach(item => {
                    item.onResolved(data);
                })
            })
        }
        // reject 函数
        function reject(data){
            //判断状态
            if(self.PromiseState !== 'pending') return;
            // 修改对象的状态(PromiseState)
            self.PromiseState = 'rejected';
            // 设置对象结果值(PromiseResult)
            self.PromiseResult = data;
            // 调用失败的回调函数
            setTimeout(()=>{
                self.callbacks.forEach(item => {
                    item.onRejected(data);
                })
            })
        }
        try{
            // 同步调用执行器函数
            executor(resolve, reject);
        }catch(e){
            // 修改 promise 对象状态为失败
            reject(e);
        }
    }

    // then 方法封装
    then(onResolved, onRejected){
        const self = this;
        // 判断回调函数参数
        if(typeof onResolved !== 'function'){
            onResolved = value => value;
        }
        if(typeof onRejected !== 'function'){
            onRejected = reason =>{
                throw reason;
            }
        }
        return new Promise((resolve, reject) => {
            // 封装函数
            function callback(type){
                try{
                    // 获取回调函数的执行结果
                    let result = type(self.PromiseResult);
                    // 判断
                    if(result instanceof Promise){
                        // 如果是 Promise 类型的对象
                        result.then(v=>{
                            resolve(v);
                        }, r=>{
                            reject(r);
                        })
                    }else{
                        //结果的对象状态为成功
                        resolve(result);
                    }
                }catch(e){
                    reject(e);
                } 
            }
            // 调用回调函数
            if(this.PromiseState === 'fulfilled'){
                // then 方法回调异步执行
                setTimeout(()=>{
                    callback(onResolved);
                }); 
            }
            if(this.PromiseState === 'rejected'){
                setTimeout(()=>{
                    callback(onRejected);
                }); 
            }
            // 判断pending状态(异步任务)
            if(this.PromiseState === 'pending'){
                // 保存回调函数
                this.callbacks.push({
                    onResolved: function(){
                        callback(onResolved);
                    }
                    onRejected: function(){
                        callback(onRejected);
                    }
                });
            }
        })
    }

    // catch 方法
    catch(onRejected){
        return this.then(undefined, onRejected);
    }

    // 添加 resolve 方法(属于promise函数对象,不是属于实例对象)
    static resolve(value){
        // 返回 promise 对象
        return new Promise((resolve, reject) => {
            if(value instanceof Promise){
                value.then(v=>{
                    resolve(v);
                }, r=>{
                    reject(r);
                })
            }else{
                //结果的对象状态为成功
                resolve(value);
            }
        });
    }

    // 添加 reject 方法
    static reject(reason){
        // 返回 promise 对象
        return new Promise((resolve, reject) => {
            reject(reason);
        });
    }

    // 添加 all 方法
    static all(promises){
        // 返回结果为 promise 对象
        return new Promise((resolve, reject) => {
            // 声明变量
            let count = 0;
            let arr = [];
            // 遍历
            for(let i=0; i<promises.length; i++){
                promises[i].then(v => {
                    // 得知对象的状态是成功
                    count++;
                    // 将当前promise对象成功的结果存入到数组中
                    arr[i] = v;
                    // 每个promise对象都成功
                    if(count === promise.length){
                        resolve(arr);
                    }
                }, r => {
                    reject(r);
                });
            }
        });
    }

    // 添加 race 方法
    static race(promises){
        return new Promise((resolve, reject) => {
            for(let i=0; i<promises.length; i++){
                promises[i].then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            }
        });
    }
}

5. async与await

5.1 async函数 

        1. 函数的返回值为Promise对象。

        2. promise对象的结果由async函数执行的返回值决定。(和then方法返回结果规则一样) 

                1)如果抛出异常,结果为rejected,reason为抛出的异常。

                2)如果返回的是非promise的任意值,结果为resolved,value为返回的值。

                3)如果返回的是另一个promise,返回promise的结果就会成为它的结果。 

5.2 await表达式 

        await右侧的表达式一般为promise对象,但也可以是其他值。

                1. 如果表达式是promise对象,await返回的是promise成功的值。

                2. 如果表达式是其他值,直接将此值作为await的返回值。 

        注意:1. await必须写在async函数中,但async函数中可以没有await。

                   2. 如果await的promise失败,就会抛出异常,需要通过try...catch捕获处理。   

5.3 async与await结合实践 

5.3.1 读取文件内容

// 读取 resource 文件夹下 3 个文件内容
const util = require('util');
const fs = require('fs');
const mineReadFile = util.promisify(fs.readFile);

async function main(){
    try{
        // 读取第一个文件的内容
        let data1 = await mineReadFile('./resource/1.txt');
        // 读取第二个文件的内容
        let data2 = await mineReadFile('./resource/2.txt');
        // 读取第三个文件的内容
        let data3 = await mineReadFile('./resource/3.txt');
    }catch(e){
        console.log(e);
    }
}

 5.3.2 发送AJAX请求

function sendAJAX(url){
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        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);
                }
            }
        } 
    });
}
async function main(){
    let data = await sendAJAX('https://xxx/xxx');
    console.log(data);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值