手动封装Promise笔记

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

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

  • Promise 支持链式调用, 可以解决回调地狱问题 1.什么是回调地狱? : 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件 3.回调地狱的缺点? : 不便于阅读 和 不便于异常处理 3.解决方案? : promise 链式调用 4.终极解决方案 :async/await

  • fs 文件操作

    require('fs').readFile('./index.html', (err,data)=>{})
    
  • AJAX

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

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

Promise 的状态

实例对象中的一个属性 『PromiseState』

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

Promise 对象的值

实例对象中的另一个属性 『PromiseResult』 保存着异步任务『成功/失败』的结果

  • resolve
  • reject

API

  1. Promise 构造函数: Promise (exqutor) {} (1) executor 函数:执行 器(resolve, reject) => {} (2) resolve 函数:内部定义成功时我们调用的函数value=> {} (3) reject 函数:内部定义失败时我们调用的函数reason=> {} 说明:executor会在Promise内部立即同步调用,异步操作在执行器中执行
  2. Promise.prototype.then 方法: (onResolved, onRejected)=> {} (1) onResolved 函数:成功的回调函数(value) => {} (2) onRejected 函数:失败的回调函数(reason) => {} 说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象
  3. Promise.prototype.catch 方法: (onRejected) => {} (1) onRejected 函数:失败的回调函数(reason) => {}
  4. Promise.resolve 方法: (valμe)=> {} (1) value: 成功的数据或promise对象 说明:返回一个成功/失败的promise对象|
  5. Promise.reject 方法: (reason) => {} (1) reason: 失败的原因说明:返回一个失败的promise对象
  6. Promise.all 方法: (promises)=> {} (1) promises: 包含n个promise的数组 说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一一个失败了就直接失败
  7. Promise.race 方法: (promises)=> {} (1) Promise: 包含n个Promise的数组 说明:返回一个新的Promise,第一个完成的Promise的结果状态就是最终的结果状态

Promise手动封装案例

class Promise {
    // 构造方法
    constructor(executor) {
        // 添加属性
        this.PromiseState = 'pending';
        this.PromiseResult = null;
        this.callbacks = []; // 保存因异步任务而丢弃的数据
        // 保存实例对象的 this 的值
        const self = this;
        // resolve 函数
        function resolve(data) {
            // console.log(this); // 这里的 this 默认指向的是 window对象
            if(self.PromiseState !== 'pending') return;
            // 1. 修改对象的状态(PromiseState)
            self.PromiseState = 'fulfilled'; // resolve
            // 2. 设置对象的结果值 (PromiseResult)
            self.PromiseResult = data;
            setTimeout(() => {
                // 3. 调用成功的回调函数
                self.callbacks.forEach(item => {
                    item.onResolved(data);
                });
            });
        }     
        // reject 函数
        function reject(data) {
            if(self.PromiseState !== 'pending') return;
            // 1. 修改对象的状态(PromiseState)
            self.PromiseState = 'rejected';
            // 2. 设置对象的结果值 (PromiseResult)
            self.PromiseResult = data;

            setTimeout(() => {
                // 3. 调用成功的回调函数
                self.callbacks.forEach(item => {
                    item.onRejected(data);
                })
            });
        }

        // 捕捉 throw 抛出的 错误 使用 try{}catch(){}
        try {
            // 同步调用 执行器函数
            executor(resolve, reject);
        }catch(e) {
            // 修改Promise对象的状态为 reject 失败
            reject(e);
        }
        
    }
    // then 方法
    then(onResolved, onRejected) {
         const self = this;
        // 判断回调函数参数
        if(typeof onRejected !== 'function') {
            onRejected = reason => {
                throw reason;
            }
        }
        if(typeof onResolved !== 'function') {
            onResolved = value => value
        }
        return new Promise((resolve, reject) => {
            // 封装判断函数
            function callback(type) {
                 try{
                     // 获取回调函数的执行结果
                    let result = type(self.PromiseResult);
                    // 判断
                    if(result instanceof Promise) {
                        // 如果是 Promise 类型的对象 通过 then 方法 来进行返回
                        result.then(v => {
                            resolve(v);
                        }, r => {
                            reject(r);
                        })
                    }else {
                    // 不是 Promise 对象的类型为成功 通过resolve变为Promise对象
                        resolve(result);
                    }
                }catch(e){
                        reject(e);
                }
            }
          
            // 调用回调函数 PromiseState
            if(this.PromiseState === 'fulfilled') {
                  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 方法
    static resolve(value) {
        return new Promise((resolve, reject) => {
            if(value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            }else {
                resolve(value);
            }
        });
    }
    // reject 方法
    static reject(reason) {
        return new Promise((resolve ,reject) => {
            reject(reason);
        });
    }
     // 添加 all 方法
    static all(promises) {
        // 声明变量 判断成功的promise
        let count = 0;
        let arr = [];
        // 返回promise对象
        return new Promise((resolve, reject) => {
            for(let i = 0; i < promises.length ; i++) {
                promises[i].then(v => {
                    // 得知成功的promis
                    count++;
                    // 将当前Promise对象成功的结果 存入到数组中
                    arr[i] = v;
                    if(count === promises.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);
                });
            }
        });
    }

}

async & await

async

<script>
        async function main() {
            // 1. 如果返回值是一个非 Promise 类型的数据 表示成功
            // return 32;
            // 如果返回的是 Promise 对象 结果看它返回的值(类型)
            /* return new Promise((resovle, reject) => {
                // resovle('OK');
                reject("Error");
            }); */
            // 3. 抛出错误
            throw "Error";
        }   
        let result = main();

        console.log(result);

    </script>

await


 <script>
        async function main() {
            let p = new Promise((resovle,reject) => {
                // resovle("OK");
                reject("Error");
            });
            // 1. 右侧为Promise对象的情况
            // let res = await p;
            // console.log(res);
            // 2. 右侧为其它类型的数据
            // let res2 = await 20;
            // console.log(res2);
            // 3. 如果Promise是失败的状态
            try {
                let res3 = await p;
            }catch(e) {
                console.log(e);
            }
          
        }
        main();
    </script>

async 和 await 读取文件

const util = require('util');
const fs = require('fs');
const read = util.promisify(fs.readFile);
/* fs.readFile('./1.Promise初体验.html', (err, data1) => {
    if(err) throw err;
    fs.readFile('./2.Promise-fs模块.js', (err, data2) => {
        if(err) throw err;
        fs.readFile('./3.Promise实践-AJAX请求.html', (err, data3) => {
            if(err) throw err;
            console.log(data1 + data2 + data3);
        });
    });
}); */

// async 和 await 
async function main() {
   try{
        let res1 = await read('./1.Promise初体验.html');
        let res2 = await read('./2.Promise-fs模块.js');
        let res3 = await read('./3.Promise实践-AJAX请求.html');
          console.log(res1 + res2 + res3);
   }catch(e){
       console.log(e);
   }
}

main();

async 和 await 发送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>Document</title>
</head>
<body>
    <button id="btn">点击获取段子</button>
    <script>
        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.statusText);
                        }
                    }
                }
            });
        }
        // 接口地址:" https://api.apiopen.top/getJoke"
        let btn = document.querySelector("#btn");
        btn.addEventListener("click",async function() {
            let duanzi = await sendAJAX("https://api.apiopen.top/getJoke");
            console.log(duanzi);
        });
    </script>
</body>
</html>