详解回调地狱以及promise

发布时间:2023-08-04 10:00

详解回调地狱以及promise_第1张图片

1.什么是回调地狱?

说promise之前必须先简单说下,回调地狱
回调地狱:在回调函数中又嵌套了多层回调函数,便会形成回调地狱
JS中或node中,都大量的使用了回调函数进行异步操作,而异步操作什么时候返回结果是不可控的,如果我们希望几个异步请求按照顺序来执行,那么就需要将这些异步操作嵌套起来,嵌套的层数特别多,就会形成回调地狱 或者叫做 横向金字塔。

例如我们创建一个文件夹,里面各自包含一句诗,要求这四个异步按顺序排列
详解回调地狱以及promise_第2张图片
如此大量使用回调函数,便会形成回调地狱

//第一步先导入fs模块
import { readFile } from 'fs'
readFile('./poetry/a.txt', 'utf-8', (err, data) => {
  console.log(data)
  readFile('./poetry/b.txt', 'utf-8', (err, data) => {
    console.log(data)
    readFile('./poetry/c.txt', 'utf-8', (err, data) => {
      console.log(data)
      readFile('./poetry/d.txt', 'utf-8', (err, data) => {
        console.log(data)
      })
    })
  })
})

详解回调地狱以及promise_第3张图片
为了解决回调地狱带来,代码难于维护和修改的弊端,ES6推出Promise对象来解决回调地狱

2.promise的基本概念

Promise对象是一个构造函数,用来生成Promise实例。是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案。
类似一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,Promise 是一个对象,使用的时候需要 new
而Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
实例中,它里面的异步操作就相当于一个承诺,而承诺就会有两种结果,要么完成了承诺的内容,要么失败。
Promise有 resolve(完成) 和 reject(失败) 两个形参
必须传入一个函数作为Promise的参数,这个函数在 new Promise的时候就会执行
将异步任务成功的结果传给 resolve 函数;将失败的信息传给 reject 函数

3.promise的基本用法(青铜)

//第一步先导入fs模块
import { readFile } from 'fs'
//第二步创建promise对象
const p1 = new Promise((resolve, reject) => {
  readFile('./poetry/a.txt', 'utf-8', (err, data) => {
    resolve(data)   //暂不做判断,不考虑错误情况
  })
})
const p2 = new Promise((resolve, reject) => {
  readFile('./poetry/b.txt', 'utf-8', (err, data) => {
    resolve(data)   //暂不做判断,不考虑错误情况
  })
})
const p3 = new Promise((resolve, reject) => {
  readFile('./poetry/c.txt', 'utf-8', (err, data) => {
    resolve(data)   //暂不做判断,不考虑错误情况
  })
})
const p4 = new Promise((resolve, reject) => {
  readFile('./poetry/d.txt', 'utf-8', (err, data) => {
    resolve(data)   //暂不做判断,不考虑错误情况
  })
})
//第三步读取文件  
const a = p1.then(res => {
  console.log(res);      //3.1 then()中的回调函数,不写返回值,默认返回一个空白的Promise对象,
                         //3.2如果返回一个真实的Promise对象,那么就会赋值给 then()
  return p2               // 3.3返回一个 Promise 对象,调用下一个 then();
})
const b = a.then(res => {
  console.log(res);
  return p3
})
const c = b.then(res => {
  console.log(res);
  return p4
})
const d = c.then(res => {
  console.log(res)
})

4.promise的封装(黄金)

Promise 实例具有then方法,then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

//第一步导入fs模块
import { readFile } from 'fs'
//第二步封装一个方法.返回一个promise对象
function getpromise(url) {
  return new Promise((resolve, reject) => {
    readFile(url, 'utf-8', (err, data) => {
      resolve(data)  //暂不做判断,不考虑错误情况
    })
  })
}
//调用
getpromise('./poetry/a.txt').then(res => {
  console.log(res);
  return getpromise('./poetry/b.txt')
}).then(res => {
  console.log(res);
  return getpromise('./poetry/c.txt')
}).then(res => {
  console.log(res);
  return getpromise('./poetry/d.txt')
}).then(res => console.log(res))

注意:then方法接收一个函数类型的参数,只处理成功
then方法接收两个函数类型的参数,分别用于接收 resolve 的值 和 reject 的值
then方法也可以只接收一个参数,表示只接收 resolve 的值,失败的结果可以通过链式调用catch方法捕获

5.promise的模块(钻石)

//需要先下载模块: npm  i   then-fs
// // 普通fs模块,readFile()返回 undefined ;
// // then-fs模块,readFile()返回 Promise 对象;
//先导入then-fs模块
import thenFs from 'then-fs'
// 读取文件
thenFs.readFile('./poetry/a.txt', 'utf8').then(res => {
  console.log(res);
  return thenFs.readFile('./poetry/b.txt', 'utf8');
}).then(res => {
  console.log(res);
  return thenFs.readFile('./poetry/c.txt', 'utf8');
}).then(res => {
  console.log(res);
  return thenFs.readFile('./poetry/d.txt', 'utf8');
}).then(res => console.log(res))

5.1Promise中的同步异步

Promise被创建的时候,执行的是同步代码;
new Promise 和 new 其他对象一样,是同步任务。
但是获取结果时(调用 resolve 触发 then方法时)是异步的。
// then()和catch()里面执行的是异步代码;

6.promise进阶(星耀)

ES2017 标准引入了 async 和 await,使得异步操作变得更加方便。

6.1 async函数

async 函数是什么?一句话,它就是 Generator 函数的语法糖。
async 用于修饰一个 function
async 修饰的函数,总是返回一个 Promise 对象
函数内的所有值,将自动包装在 resolved 的 promise 中

async function fn() {
  return 666
}
let result = fn()
console.log(result)  //Promise { 666 }
result.then(res => console.log(res))   //666

6.2 await命令

正常情况下await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
await只能出现在异步函数中!
await能停止代码执行,让后面的同步代码,先执行
await后面跟随的是一个promise对象
await返回的是: Promise对象中的then()中的回调函数中的参数res

async function fn() {
  return 666
}
console.log('嘻嘻')  //第一个同步先执行

async function fn2() {
  console.log('哈哈')    //第二个同步  
  let str = await fn()   // await会 暂停函数的执行  但不会影响同步
  console.log(str)
  console.log(888);
}
fn2()
console.log(333)           //第三个同步
let result = fn()

6.3加入async和await

//先导入then-fs模块
import thenFs from "then-fs";
async function getpromise() {
  const a = await thenFs.readFile('./poetry/a.txt', 'utf8')
  const b = await thenFs.readFile('./poetry/b.txt', 'utf8')
  const c = await thenFs.readFile('./poetry/c.txt', 'utf8')
  const d = await thenFs.readFile('./poetry/d.txt', 'utf8')
  console.log(a)
  console.log(b)
  console.log(c)
  console.log(d)
}
getpromise()

7.promise解决回调地狱(王者)
await需要等待promise执行完毕,所以 await会 暂停函数的执行,但不会影响其他同步任务。
await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中
7.1promise三种状态
Promise对象代表一个异步操作,
有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
一旦状态改变,就不会再变
状态的改变只有两种可能:
从pending(进行中)变为fulfilled(已成功)
从pending(进行中)变为rejected(已失败)
当达到最终的 fulfilled 或 rejected 时,promise的状态就不会再改变了。

7.2Promise.prototype.finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
下面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行

// 先导入then-fs
import thenFs from 'then-fs';
async function fn() {
  try {
    const str1 = await thenFs.readFile('./poetry/a.txt', 'utf8');
    console.log(str1);
    const str2 = await thenFs.readFile('./poetry/b.txt', 'utf8');
    console.log(str2);
    const str3 = await thenFs.readFile('./poetry/c.txt', 'utf8');
    console.log(str3);
    const str4 = await thenFs.readFile('./poetry/d.txt', 'utf8');
    console.log(str4);
  } catch (e) {
    console.log("文件读取错误: " + e.message);
  } finally {
    console.log('无论有没有错误都要执行的代码...');
  }
}
fn();

未完待续…

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号