• Promise入门


    一、Promise 的基本使用

    1.1、Promise 简介

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

    Promise对象有以下两个特点。

    (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

    1.2、Promise 的基本使用

    新建的Promise就是一个容器,里面可以存放异步操作,也可以存放同步操作

    const fs = require("fs");
    const path = require("path");
    
    let filePath = path.join(__dirname, "files", "3.txt");
    
    // 异步操作可能成功或者失败
    // 第一个形参resolve , 成功的时候执行的函数
    // 第二个形参reject , 失败的时候执行的函数
    let p1 = new Promise((resolve, reject)=>{
        //1、同步代码
        console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1);    // 调用后面p1.then的第二个函数
            }
            //读取完之后做的事情
            resolve(data1);    // 调用后面p1.then的第二个函数
        })
    });
    
    p1.then((data1)=>{
        console.log("读取成功", data1);
    },(error1)=>{
        console.log("读取失败", error1);
    });
    

    1.3、Promise的then链式调用的特点

    链式调用的特点:
    1、第一个then执行完会执行第二个then
    2、then里面的函数的返回值,会被下一个then的形参接收
    3、如果返回的是一个promise对象,下一个then的形参接收到的不是这个promise对象,而是这个promise对象内部调用resolve时候的实际参数

    const fs = require("fs");
    const path = require("path");
    
    let filePath = path.join(__dirname, "files", "3.txt");
    
    // 新建的Promise就是一个容器,里面可以存放异步操作,也可以存放同步操作
    
    // 异步操作可能成功或者失败
    // 第一个形参resolve , 成功的时候执行的函数
    // 第二个形参reject , 失败的时候执行的函数
    let p1 = new Promise((resolve, reject)=>{
        //1、同步代码
        // console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1)
            }
            //读取完之后做的事情
            resolve("resolve的形参")
        })
    });
    
    //业内把promise then的写法被称为开火车开发
    
    p1.then((data1)=>{
        return p1
    },(error1)=>{
        console.log("读取失败", error1);
        return error1
    }).then((data)=>{
        console.log(data);   // “resolve("resolve的形参")
    });
    

    二、使用promise实现之前文件读取的案例

    2.1、基础版

    //基础版
    const fs = require("fs");
    const path = require("path");
    
    let filePath1 = path.join(__dirname, "files", "1.txt"); // 我
    let filePath2 = path.join(__dirname, "files", "2.txt"); // 爱
    let filePath3 = path.join(__dirname, "files", "3.txt"); // Node.js
    
    
    let p1 = new Promise((resolve, reject)=>{
        //1、同步代码
        // console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath1,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1);
            }
            //读取完之后做的事情
            resolve(data1)
        })
    });
    let p2 = new Promise((resolve, reject)=>{
        //1、同步代码
        // console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath2,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1);
            }
            //读取完之后做的事情
            resolve(data1)
        })
    });
    let p3 = new Promise((resolve, reject)=>{
        //1、同步代码
        // console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath3,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1)
            }
            //读取完之后做的事情
            resolve(data1)
        })
    });
    
    let str1 = "";
    
    p1.then((data)=>{
        str1+=data;
        return p2
    },(error1)=>{
        console.log("读取文件1失败", error1);
        return error1
    }).then((data)=>{
        str1+=data;
        return p3;
    }).then((data)=>{
        str1+=data;
        console.log(str1);
    });
    
    

    2.2、封装函数版

    const fs = require("fs");
    const path = require("path");
    
    let filePath1 = path.join(__dirname, "files", "1.txt");
    let filePath2 = path.join(__dirname, "files", "2.txt");
    let filePath3 = path.join(__dirname, "files", "3.txt");
    
    function readFilePromise(filePath){
        return new Promise((resolve, reject)=>{
    
            fs.readFile(filePath,"utf-8",(error1, data1)=>{
                if(error1){
                    //失败的时候做的事情
                    reject(error1);
                }
                //读取完之后做的事情
                resolve(data1)
            })
        });
    }
    
    let str1 = "";
    
    readFilePromise(filePath1).then((data)=>{
        str1+=data;
        return readFilePromise(filePath2)
    },(error1)=>{
        console.log("读取文件1失败", error1);
        return error1
    }).then((data)=>{
        str1+=data;
        return readFilePromise(filePath3);
    }).then((data)=>{
        str1+=data;
        console.log(str1);
    });
    

    2.3、util版本

    node中有一个util工具模块下,有一个promisify方法,这个方法相当于封装了一个返回promise对象的函数。

    文档网址:http://nodejs.cn/api/util.html#util_util_promisify_original

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

    let readFilePromise = util.promisify(fs.readFile);  //这一句代码相当于下面的整个函数的代码
    // function readFilePromise(filePath){
    //     return new Promise((resolve, reject)=>{
    //
    //         fs.readFile(filePath,"utf-8",(error1, data1)=>{
    //             if(error1){
    //                 //失败的时候做的事情
    //                 reject(error1);
    //             }
    //             //读取完之后做的事情
    //             resolve(data1)
    //         })
    //     });
    // }
    
    // 总结 :util.promisify(fs.readFile) 得到一个promise对象
    

    完整代码:

    const fs = require("fs");
    const path = require("path");
    const util = require("util");
    
    let filePath1 = path.join(__dirname, "files", "1.txt");
    let filePath2 = path.join(__dirname, "files", "2.txt");
    let filePath3 = path.join(__dirname, "files", "3.txt");
    let filePath4 = path.join(__dirname, "files", "data.txt");
    
    let readFilePromise = util.promisify(fs.readFile); 
    let writeFilePromise = util.promisify(fs.writeFile);
    
    let str1 = "";
    
    readFilePromise(filePath1).then((data)=>{
        str1+=data;
        return readFilePromise(filePath2)
    },(error1)=>{
        console.log("读取文件1失败", error1);
        return error1
    }).then((data)=>{
        str1+=data;
        return readFilePromise(filePath3);
    }).then((data)=>{
        str1+=data;
        console.log(str1);
        writeFilePromise(filePath4, str1);
    });
    

    2.4、all版本

    const fs = require("fs");
    const path = require("path");
    const util = require("util");
    
    let filePath1 = path.join(__dirname, "files", "1.txt");
    let filePath2 = path.join(__dirname, "files", "2.txt");
    let filePath3 = path.join(__dirname, "files", "3.txt");
    let filePath4 = path.join(__dirname, "files", "data.txt");
    
    let readFilePromise = util.promisify(fs.readFile);  //这一句代码相当于下面的整个函数的代码
    let writeFilePromise = util.promisify(fs.writeFile);
    
    Promise.all([readFilePromise(filePath1,"utf-8"), readFilePromise(filePath2,"utf-8"),readFilePromise(filePath3,"utf-8")]).then((data)=>{
        let str1 = data.join("");
        writeFilePromise(filePath4,str1);
    }).catch((error)=>{
        //只要执行p1,p2时其中一个报错,就会执行这里的代码
        console.log(error);
    });
    

    2.5、async+await版本

    const fs = require("fs");
    const path = require("path");
    const util = require("util");
    
    let filePath1 = path.join(__dirname, "files", "1.txt");
    let filePath2 = path.join(__dirname, "files", "2.txt");
    let filePath3 = path.join(__dirname, "files", "3.txt");
    let filePath4 = path.join(__dirname, "files", "data.txt");
    
    let readFile = util.promisify(fs.readFile);
    let writeFile = util.promisify(fs.writeFile);
    
    async function func() {
        let data1 = await readFile(filePath1, "utf-8");
        let data2 = await readFile(filePath2, "utf-8");
        let data3 = await readFile(filePath3, "utf-8");
    
        console.log(data1+data2+data3);
    
        writeFile(filePath4, data1+data2+data3)
    }
    
    func();
    

    三、Promise的常用其他方法

    3.1、promise对象catch()方法和finally()方法

    //一般,我们会把以下代码:
    p1.then((data1)=>{
        console.log("承诺成功", data1);
    },(error1)=>{
        console.log("承诺失败", error1);
    });
    
    //写成
    p1.then((data1)=>{
        console.log("承诺成功", data1);
    }).catch((error1)=>{
        console.log("承诺失败", error1);
    }).finally(()=>{
        console.log("承诺成功与失败都会执行这里的代码");
    });
    
    

    3.2、Promise类的all() 方法

    参数:是一个数组,数组元素是Promise实例对象,只有数组里面所有的Promise成功了,则才会执行 then 第一个回调

    const fs = require("fs");
    const path = require("path");
    
    let filePath1 = path.join(__dirname, "files", "1.txt");
    let filePath2 = path.join(__dirname, "files", "2.txt");
    
    
    let p1 = new Promise((resolve, reject)=>{
        //1、同步代码
        // console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath1,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1);
            }
            //读取完之后做的事情
            resolve(data1)
        })
    });
    let p2 = new Promise((resolve, reject)=>{
        //1、同步代码
        // console.log("同步代码");
    
        // pending(进行中)、fulfilled(已成功)和rejected(已失败)
        //2、异步代码
        fs.readFile(filePath2,"utf-8",(error1, data1)=>{
            if(error1){
                //失败的时候做的事情
                reject(error1);
            }
            //读取完之后做的事情
            resolve(data1)
        })
    });
    
    Promise.all([p1,p2]).then((data)=>{
        // data是一个数组,分别是p1和p2最后传来的数据
        console.log(data); // [ '我', '爱' ]
        console.log(data.join(""));  // 我爱
    }).catch((error)=>{
        //只要执行p1,p2时其中一个报错,就会执行这里的代码
        console.log(error);
    });
    

    3.3、Promise类的race() 方法

    参数:是一个数组,数组元素是Promise实例对象,只要数组里面的任何一个Promise成功了,则才会执行 then 第一个回调,且只执行1次。

    const fs = require("fs")
    const path = require("path")
    const util = require('util');
    
    let filePath1 = path.join(__dirname, "files", "1.txt") 
    let filePath2 = path.join(__dirname, "files", "2.txt") 
    
    let readFilePromise = util.promisify(fs.readFile);
    
    let p1 = readFilePromise(filePath1,"utf-8")
    let p2 = readFilePromise(filePath2,"utf-8")
    Promise.race([p1,p2]).then((data)=>{
        // p1,p2只要其中一个执行完,就会执行一遍这里的代码,且这里的代码只会执行1次
        console.log(123);
        console.log(data);
    });
    
    //123
    //我
    

    四、async+await

    4.1 async+await 终极版

    看下面这一段代码:

    function func(a, b) {
        return a + b
    }
    
    let ret = func(10, 30);
    let ret1 = func(50, 320);
    let ret2 = func(1560, 30);
    let ret3 = func(10, 3560);
    console.log(ret + ret1 + ret2 + ret3);
    

    如果Promise对象也能有对应的方式来接收,写成类似:

    let data1 = await readfilePromise;  // 直接获取成功的数据
    

    async 的最终格式如下:

    async function func() {
        let data1 = await promise对象1;
        let data2 = await promise对象2;
        let data3 = await promise对象3;
    }
    // 相当于让异步函数对象1先执行完毕之后,再执行异步函数对象2,再执行异步函数对象3
    

    4.2、注意事项

    1. 如果await后面只写一个基本数据类型,会这个基本数据类型进行包装,包装成一个 Promise 对象
    async function func() {
        let data1 = await 123;
        //1. await后面只写一个基本数据类型 会这个基本数据类型进行包装,包装成一个 Promise 对象
        // 即data1相当于: new Promise((resolve,reject)=>{resolve(123)})
    
        console.log("data1:", data1);   //data1: 123
    
        return data1
        // return await data1
    
    }
    
    let a = func();
    
    a.then((data)=>{
        console.log(data);  //123  接收到上面的返回值Promise对象的执行结果
    });
    
    1. 如果await后面是一个 Promise,会把 resolve 的值返回
    2. async 函数里面的 await 是异步的,不是同步
    async function func() {
        console.log("start-------");
        let data1 = await readFile(filePath1, "utf-8");
        console.log("end-----------");
        let data2 = await readFile(filePath2, "utf-8");
        let data3 = await readFile(filePath3, "utf-8");
    
        console.log(data1+data2+data3);
    }
    
    console.log("start");
    func();
    console.log("end");
    
    //输出结果依次为:
    //start
    //start-------
    //end
    //end-----------
    
    1. 错误处理(外部处理)
    async function func() {
        let data1 = await readFile(filePath1, "utf-8");
        let data2 = await readFile(filePath2, "utf-8");
        let data3 = await readFile(filePath3, "utf-8");
    
        console.log(data1+data2+data3);
    
        // writeFile(filePath4, data1+data2+data3)
    }
    
    func().catch( error => {
        console.log(error);
    } ).finally(()=>{
        console.log("finally");
    });
    
    1. 错误处理(内部处理)
    async function func() {
        try{
            let data1 = await readFile(filePath1, "utf-8");
            let data2 = await readFile(filePath2, "utf-8");
            let data3 = await readFile(filePath3, "utf-8");
        }
        catch (error) {
            console.log(error);
            return
        }
        finally {
            console.log("finally");
        }
    
        console.log("end");
    }
    
    func();
    
  • 相关阅读:
    hdu1879 继续畅通工程
    hdu1875 畅通工程再续 最小生成树并查集解决---kruskal
    hdu1863 畅通工程2 还是用并查集思想解决最小生成树问题
    hud2544dijkstra+堆优化
    PHP holiday1
    记忆化搜索hdu1078 dfs
    hdu 1548 楼梯 bfs或最短路 dijkstra
    隐藏原生html5 video controls
    工具网站gallery
    判断节点包含
  • 原文地址:https://www.cnblogs.com/Liwker/p/15920717.html
Copyright © 2020-2023  润新知