Promise基本使用

1. Promise的基本概念

  1. Promise是一个构造函数
    • 我们可以创建Promise的实例 const p =new Promise()
    • new 出来的Promise实例对象,代表一个异步操作
  2. Promise.prototype上包含一个.then()方法
    • 每一次new Promise()构造函数得到的实例对象都可以通过原型链的方式访问到.then()方法,例如p.then()
  3. .then()方法可以预先指定成功和失败的回调函数
    • p.then(成功的回调函数,失败的回调函数)
    • p.then(result=>{},error=>{})
    • 调用回调函数时,成功的回调是必选的,失败的回调是可选的

2. 基于then-fs读取文件内容

由于node.js官方提供的fs模块仅支持以回调函数的方式读取文件,不支持Promise的调用方式。因此,需要先安装

then-fs第三方包,从而支持我们基于Promise的方式读取文件内容

运行如下命令下载then-fs包

npm i then-fs

下载安装完成后调用then-fs提供的readFile()方法,可以异步地读取文件的内容,它的返回值是Promise的实例对象。因此可以调用.then()方法为每个Promise异步操作指定成功和失败后的回调函数。示例代码如下:


import thenFs from 'then-fs'

thenFs.readFile('./Promise/files/1.txt','utf8').then(r1=>{console.log(r1)},err1=>{console.log(err1.message)})
thenFs.readFile('./Promise/files/2.txt','utf8').then(r2=>{console.log(r2)},err2=>{console.log(err2.message)})
thenFs.readFile('./Promise/files/3.txt','utf8').then(r3=>{console.log(r3)},err3=>{console.log(err3.message)})

结果如下:

image-20221230122652037

正常顺序是“111,222,333”,可见异步调用无法保证读取文件顺序

如果要保证读取顺序,则通过如下代码实现,同时解决了回调地狱问题

thenFs.readFile('./Promise/files/1.txt','utf8')
   .then(r1=>{
    console.log(r1)
    return thenFs.readFile('./Promise/files/2.txt','utf8')
   })
   .then(r2=>{
    console.log(r2)
    return thenFs.readFile('./Promise/files/3.txt','utf8')
   })
   .then(r3=>{
    console.log(r3)
   })

3. Promise.all()方法

Promise.all()方法会发起并行的Promise异步操作,等所有的异步操作全部结束后才会执行下一步的.then操作(等待机制)。

示例代码如下:

onst promiseArr = [
    thenFs.readFile('./Promise/files/1.txt','utf8'),
    thenFs.readFile('./Promise/files/2.txt','utf8'),
    thenFs.readFile('./Promise/files/3.txt','utf8')
]
Promise.all(promiseArr)
    .then(([r1,r2,r3])=>{
        console.log(r1,r2,r3)
    })
    .catch((err)=>{
        console.log(err.message)
    })

打印结果顺序和数组声明顺序相同

4. Promise.race()方法

race()方法就是赛跑机制的实现,即只要有一个promsie执行完成后就立刻执行.then()操作(赛跑机制)


const promiseArr = [
    thenFs.readFile('./Promise/files/1.txt','utf8'),
    thenFs.readFile('./Promise/files/2.txt','utf8'),
    thenFs.readFile('./Promise/files/3.txt','utf8')
]
Promise.race(promiseArr)
    .then((res=>{
        console.log(res)
    }))
    .catch((err)=>{
        console.log(err.message)
    })

打印结果是111,222,333中的任意一个.

4. 创建自定义异步操作

import thenFs from "fs";

function getFile(fpath){

    return new Promise(function(resolve,reject){
        thenFs.readFile(fpath, 'utf8', (err,dataStr)=>{
             if(err)return reject(err)
             resolve(dataStr)
        })
    })
}

getFile('./Promise/files/1.txt').then(success=>{
    console.log(success)
},error=>{
    console.log(error)
})

success回调函数对应于resolve,error回调函数对应于reject

运行结果如图:

image-20221230181037329

5. async/await

async/await是ES8引入的新语法,用来简化Promise异步操作。在async/await出现之前,开发者只能通过链式.then()的方式

处理Promise异步操作。

  • .then链式调用的优点:解决了回调地狱的问题
  • .then链式调用的缺点:代码冗余、阅读性差、不易理解
import thenFs from "then-fs";
async function getAllFile(){
    const r1 = await thenFs.readFile('./Promise/files/1.txt','utf8');
    console.log(r1)
}
getAllFile()

aysnc和await必须搭配使用,这样就可以避免用.then()方式调用

async/await使用注意事项

  • 如果在function中使用了await,则function必须被async修饰
  • 在async方法中,第一个await之前的代码会同步执行,await之后的代码会异步执行

如:

import thenFs from "then-fs";
console.log('A')
async function getAllFile(){
    console.log('B')
    const r1 = await thenFs.readFile('./Promise/files/1.txt','utf8');
    console.log(r1)
    const r2 = await thenFs.readFile('./Promise/files/2.txt','utf8');
    console.log(r2)
    const r3 = await thenFs.readFile('./Promise/files/3.txt','utf8');
    console.log(r3)
}
getAllFile()
console.log('C')

在这里主线程打印‘B’碰到await后便开启另一个线程,于是主线程接着打印‘C’,等await方法执行完后打印r1,r2,r3

image-20221230191037461

最后修改:2023 年 01 月 10 日
如果觉得我的文章对你有用,请随意赞赏