promise解析

Promise 是 JavaScript 中用于异步编程的一个重要概念。它表示一个尚未完成但预期将来会完成的操作的结果。使用 Promise 可以优雅地处理异步操作及其结果,避免回调地狱(callback hell)的出现。下面我将从基本概念、创建和使用 Promise、以及常见的方法等方面进行解析。

1. 基本概念

  • Promise 状态:Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise 创建时处于 pending 状态,可以转变为 fulfilled 或 rejected 状态,并且状态一旦改变就不会再变。
  • resolve:当异步操作成功时,我们调用这个函数,将 Promise 的状态从 pending 变为 fulfilled。
  • reject:当异步操作失败时,我们调用这个函数,将 Promise 的状态从 pending 变为 rejected。

2. 创建和使用 Promise

创建一个 Promise 对象非常简单,只需要使用 new Promise() 构造函数并传入一个执行器函数(executor function),这个函数接受两个参数:resolvereject

setTimeout(() => {     // 第一层回调函数

    console.log('延迟1秒后输出')
    setTimeout(() => {      // 第二层回调函数

        console.log('延迟2秒后输出')
        setTimeout(() => {      // 第三层回调函数

            console.log('延迟3秒后输出')
        }, 3000)
    }, 2000)
}, 1000)

回调地狱的缺点:

  • 代码耦合性太强,牵一发而动全身,难以维护
  • 大量的代码冗余相互嵌套,代码的可读性差

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

2.Promise

Promise是一个构造函数

const p = new Promise()
  • new 出来的Promise实例对象,代表一个异步操作

查看Promise实例

console.dir(promise)

可以看到prototype上有then()方法
Promise的.then()方法

​ Promise.prototype上挂载了.then()方法,每一次new Promise()得到的实例对象,都可以通过原型链的方式访问到.then()方法 如 p.then()。

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

p.then(result=>{},err=>{})
  • .then()方法用来预先指定成功失败的回调函数
  • 调用.then()方法时,成功的回调函数是必选的,失败的回调函数是可选的

(1)基于回调函数读取文件

import fs from 'fs'

fs.readFile('./file/01.txt', 'utf8', (err1, res1) => {

    if (err1) return console.log(res1.message)
    console.log(res1)     // 123    读取文件1成功
    fs.readFile('./file/02.txt', 'utf8', (err2, res2) => {

        if (err2) return console.log(err2.message)
        console.log(res2)  // 456           读取文件2成功
        fs.readFile('./file/03.txt', 'utf8', (err3, res3) => {

            if (err3) return console.log(err3.message)
            console.log(res3)   // 789              读取文件3成功
        })
    })
})
  • 可以看到出现了回调地狱的问题

(2)基于Promise异步读取文件

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

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

import thenFs from 'then-fs'

thenFs.readFile('./file/01.txt', 'utf8').then(res1 => { console.log(res1) })
thenFs.readFile('./file/02.txt', 'utf8').then(res2 => { console.log(res2) })
thenFs.readFile('./file/03.txt', 'utf8').then(res3 => { console.log(res3) })

调用then-fs提供的readFile()方法,可以异步读取文件内容,thenFs.readFile()的返回值是Promise实例对象
因此可以调用.then()为每个Promise异步操作指定成功和失败的回调函数
由于是异步操作,得到的顺序不一
(3)基于Promise的链式调用

import thenFs from "then-fs"

thenFs.readFile('./file/10.txt', 'utf8').catch(err => {
    console.log(err.message)    
}).then(r1 => {
    console.log(r1)            
    return thenFs.readFile('./file/02.txt', 'utf8')     
}).then(r2 => {                                         

    console.log(r2)             
    return thenFs.readFile('./file/03.txt', 'utf8')     
}).then(r3 => {                                         
    console.log(r3)             
})

在第一个.then()中返回了一个新的Promise实例对象,继续调用.then(),为上一个.then的返回值(新的Promise实例),指定成功之后的回调函数
Promise的链式操作中如果发生了错误,可以使用Promise.prototype.catch方法进行捕获处理
如果不希望前面的错误导致后续的.then无法正常执行,则可以将.catch的调用提前(.catch放在最后的话前面产生的错误会导致后面.then无法被执行)
.then()方法的特性:

如果上一个.then()方法中返回了一个新的Promise实例对象,则可以通过下一个.then()继续进行处理。

通过.then()方法的链式调用,解决回调地狱问题

(4)Promise.all()

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

import thenFs from "then-fs"

const promiseArr = [

    // 三个异步读文件的promise实例
    thenFs.readFile('./file/01.txt', 'utf8'),
    thenFs.readFile('./file/02.txt', 'utf8'),
    thenFs.readFile('./file/03.txt', 'utf8')
]

Promise.all(promiseArr).then(res => {    // promise实例的顺序就是最终拿到的结果的顺序
    console.log(res)    // ['123','456','789']
}).catch(err => {
    console.log(err.message)
})
  • Promise.all() 等待所有的异步操作完成,拿到所有操作的结果

(5)Promise.race()

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

import thenFs from "then-fs"

const promiseArr = [

    // 三个异步读文件的promise实例
    thenFs.readFile('./file/01.txt', 'utf8'),
    thenFs.readFile('./file/02.txt', 'utf8'),
    thenFs.readFile('./file/03.txt', 'utf8')
]

Promise.race(promiseArr).then(res => {  // 只要任何一个异步操作完成,就立即执行成功的回调函数
    console.log(res)
}).catch(err => {
    console.log(err.message)
})

方法接收一个形参 fpath,代表要读取文件的路径
方法的返回值为Promise实例对象
new Promise() 只是创建了一个形式上的异步操作
如果想要创建具体的异步操作,则需要在new Promise()构造函数期间,传递一个function()函数, 将具体的异步操作定义到function函数内部
3.async/await

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

链式.then()调用的优点:

解决了回调地狱的问题
链式.then()调用的缺点:

代码冗余,阅读性差,不易理解
(1)使用async/await简化Promise异步操作

import thenFs from "then-fs"

async function getFile() {         
    
    const r1 = await thenFs.readFile('./file/01.txt', 'utf8')        
    console.log(r1)

    const r2 = await thenFs.readFile('./file/02.txt', 'utf8')
    console.log(r2)

    const r3 = await thenFs.readFile('./file/03.txt', 'utf8')
    console.log(r3)

}

getFile()

如果方法内部用到了await,这个方法就必须被async修饰
加了await后,thenFs.readFile()返回的就不再是promise实例,而是得到了异步操作后具体的内容
有了async和await就不需要.then()来获得最后的结果了
(2)async和await的注意事项

import thenFs from "then-fs"

console.log('A')
async function getFile() {

    console.log('B')
    const r1 = await thenFs.readFile('./file/01.txt', 'utf8')
    const r2 = await thenFs.readFile('./file/02.txt', 'utf8')
    const r3 = await thenFs.readFile('./file/03.txt', 'utf8')
    console.log(r1)
    console.log(r2)
    console.log(r3)
    console.log('D')

}

getFile()		// A B C 123 456 789 D
console.log('C')	
  • 在async方法中,第一个await之前执行的代码会同步执行,await之后执行的代码会异步执行
  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值