学Vue前的前置知识-Promise

  • Post author:
  • Post category:vue




1. 回调地狱

多层回调函数的相互嵌套,就形成了回调地狱。

如下:

setTimeout(() => {//第一层回调函数
  console.log('延时1秒后输出')
  setTimeout(() => {//第二层回调函数
    console.log('再延时2秒后输出')
    setTimeout(() => {//第三层回调函数
      console.log('再延时3秒后输出')
    },3000)
  },2000)
},1000)

不断地嵌套,不断地缩进,使代码难以阅读、难以维护。



1.1解决回调地狱的问题

为了解决回调地狱的问题,ES6(ECMAScript2015)中新增了Promise的概念。



1.2Promise的基本概念

①Promise是一个构造函数

● 可以使用new关键词创建Promise实例

● new出来的Promise实例对象,代表一个异步操作

②Promise.prototype原型对象上包含一个 .then()方法

每一次new Promise()构造函数得到的实例对象,都可以通过原型链的方式访问到.then()方法,例如p.then()

③.then()方法用来预先指定成功和失败的回调函数

● p.then(成功的回调函数,失败的回调函数)

● p.then(result => {},error => {})

● 调用.then()方法时,成功的回调函数是必选的、失败的回调函数是可选的



2. 基于回调函数按顺序读取文件内容

在这里插入图片描述

按照顺序读取文件夹📂中的文件

//读取文件1.txt
fs.readFile( './files/1.txt ', 'utf8', (err1, r1) =>{
 if (err1) return console.log(err1.message) //读取文件1失败  
 console.log(r1) //读取文件1成功
 //读取文件 2.txt
 fs.readFile( './files/2.txt ','utf8 ', (err2,r2)=>{
   if (err2) return console.log(err2.message) //读取文件2失败
   console.log(r2) //读取文件2成功
   //读取文件 3.txt
   fs.readFile( './files/3.txt','utf8', (err3,r3) =>{
     if (err3) return console.log(err3.message)//读取文件3失败
     console.log(r3)//读取文件3成功
    })
  })
})

为保证读取的顺序,读取文件的函数往内又嵌套了两层,但是同时也形成了回调地狱。



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

由于node.js官方提供的fs模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需要先运行如下的命令,安装 then-fs这个第三方包,从而支持我们基于Promise的方式读取文件的内容:

npm install then-fs



3.1. then-fs的基本使用

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

如下所示:

import thenfs from 'then-fs'

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

通过then-fs提供的readFile()方法可以读取文件,但是无法保证文件的读取顺序,还需要进一步改造。

在这里插入图片描述



3.2. then()方法的特性

如果上一个.then()方法中返回了一个新的Promise实例对象,则可以通过下一个.then()继续进行处理。通过then()方法的链式调用,就解决了回调地狱的问题。



3.3. 基于Promise按顺序读取文件的内容

promise支持链式调用,从而来解决回调地狱的问题。

如下:

thenFs.readFile('./files/1.txt ', 'utf8 ')// 1.返回值是 Promise的实例对象.then((r1) => { //2.通过 .then为第一个 Promise 实例指定成功之后的回调函数
console.log(r1)
  return thenFs.readFile( './files/2.txt ''utf8')// 3.在第一个.then中返回一个新的 Promise 实例对象})
.then((r2) => {//4.继续调用.then,为上一个.then的返回值(新的 Promise实例)指定成功之后的回调函数
 console.log(r2)
return thenFs. readFile('./files/3.txt ''utf8 ') // 5.在第二个.then 中再返回一个新的Promise 实例对象})
.then((r3)=>{//6、继续调用.then,为上一个.then 的返回值(新的 Promise 实例)指定成功之后的回调函数
 console.log(r3)
}



3.4. 通过.catch捕获错误

在Promise的链式操作中如果发生了错误,可以使用Promise.prototype.catch方法进行捕获和处理:

 import thenFs from 'then-fs'

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

.catch((err) => { console.log(err.message); })

如果不希望前面的错误导致后续的.then无法正常执行,则可以将.catch的调用提前,如下:

import thenFs from 'then-fs'

thenFs.readFile('./files/11.txt', 'utf8')
    .catch((err) => {
        console.log(err.message);
    })
    .then((r1) => {
        console.log(r1)
        return thenFs.readFile('./files/2.txt', 'utf8')
    })
    .then((r2) => {
        console.log(r2)
        return thenFs.readFile('./files/3.txt', 'utf8')
    })
    .then((r3) => {
        console.log(r3)
    })



3.5. Promise.all()方法

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

import thenFs from "then-fs";

const promiseArr = [
    thenFs.readFile('./files/1.txt', 'utf8'),
    thenFs.readFile('./files/2.txt', 'utf8'),
    thenFs.readFile('./files/3.txt', 'utf8')
]

Promise.all(promiseArr).then(result => {
    console.log(result);
})



3.6. Promise.race()方法

Promise.race()方法会发起并行的Promise异步操作,只要任何一个异步操作完成,就立即执行下一步的.then操作(赛跑机制)。如下:

import thenFs from "then-fs";

const promiseArr = [
    thenFs.readFile('./files/1.txt', 'utf8'),
    thenFs.readFile('./files/2.txt', 'utf8'),
    thenFs.readFile('./files/3.txt', 'utf8')
]

Promise.race(promiseArr).then(result => {
    console.log(result);
})



4. 基于Promise封装读文件的方法

方法封装的要求:

● 方法的名称要定义为getFile

● 方法接收一个形参发fpath,表示要读取的文件路径

● 方法的返回值为Promise实例对象



4.1. getFile方法的基本定义

function getFile(fpath){
  //方法的返回值为Promise的实例对象
  return new Promise()
}

上面代码中最后一行中的 new Promise() 只是创建了一个形式上的异步操作。



4.2. 创建具体的异步操作

如果想要创建具体的异步操作,则需要在new Promise()构造函数期间,传递一个function函数,将具体的异步操作定义到function函数内部。示例代码如下:

import fs from 'fs'

function fetFile(fpath) {
    return new Promise(function() {
        fs.readFile(fpath, 'utf8', (err, dataStr) => { })
    })
}



4.3. 获取.then的两个实参

通过.then()指定的成功和失败的回调函数,可以在function的形参中进行接收,代码如下:

function getFile(fpath) {
//resolve 形参是:调用 getFiles()方法时,通过 .then 指定的“成功的”回调函数
//reject形参是:调用 getFiles()方法时,通过 .then指定的“失败的”回调函数
return new Promise(function(resolve,reject){
  fs.readFile(fpath,'utf8',(err,dataStr => {})
 })
}

在这里插入图片描述



4.4. 调用resolve和reject回调函数

promise 异步操作的结果,可以调用resolve或 reject回调函数进行处理。示例代码如下:

function getFile(fpath) {
//resolve是“成功的”回调函数; reject是“失败的”回调函数
return new Promise(function(resolve,reject){
  fs.readFile(fpath,'utf8', (err,dataStr) => {
    if(err) return reject(err) // 如果读取失败,则调用"失败的回调函数”  
    resolve(dataStr)       //如果读取成功,则调用“成功的回调函数”
  })
 )}
 
//getFile方法的调用过程:
getFile( './files/1.txt ' ).then(成功的回调函数,失败的回调函数)



版权声明:本文为qq_33684403原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。