Promise异步编程-异步终极解决方案async+await-node.js初级(三)

Promise简介:

        Promise是异步编程的一种解决方案,ES6将其写入语言标准,统一了语法,原生提供了Promise对象。

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

        Promise对象有两个特点:

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

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

        可能还是有一些抽象,接下来进行具体的讲解。

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);
});

Promise的then链式调用的特点

链式调用的特点:

1、第一个then执行完会接着执行第二个then。

2、then里面的函数的返回值,会被下一个then的形参接收。

3、如果返回的是一个Promse对象,下一个then的形参接收的不是这个Pormise对象,而是这个Promise对象内部调用resolved时的实际参数

扫描二维码关注公众号,回复: 14126059 查看本文章
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实现文件的读取

//基础版
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");

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);
});

也可以封装函数:

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);
});

        使用util也可以,在node中的util工具里面,有一个promisify方法,这个方法相当于封装了一个返回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对象

使用util的完整代码如下:

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);

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);
});

也可以使用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);
});

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("承诺成功与失败都会执行这里的代码");
});

race()方法

race方法的参数是一个数组,数组元素要是Promise实例对象,只要函数里面的任何一个Promise成功了,则执行then里面的回调,且只执行一次。

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);
});

异步终极解决方案async+await

基本格式:

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

注意事项:

如果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对象的执行结果
});

        如果await后面是一个Promise,会把resolve的值返回

        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-----------

这属于什么,就是说start一个宏任务,func一个宏任务,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");
});



就是使用func外部的catch方法进行错误处理

2、在func内部处理:

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();

        这就是Promise在node里面的基本使用,主要逻辑还是要去看异步的宏任务和微任务,赶紧去翻我之前的文章!!!

猜你喜欢

转载自blog.csdn.net/qq_53087870/article/details/120136054