promise处理异步程序,解决回调地狱,then方法的链式调用,async/await 简化Promise异步操作,宏任务和微任务

目录

前言

一、promise说明概述

二、使用promise分为两大部分

三、promise的三种状态

四、同步和异步问题

五、then方法的链式调用

概述说明

实现原理

封装按顺序异步读取文件的函数

六、promise的静态方法

Promise.all()

Promise.race()

七、async/await 简化Promise异步操作

async/await概述说明

简化代码

async/await的使用注意事项

八、宏任务和微任务

eventloop

宏任务和微任务说明

宏任务和微任务的执行顺序

经典面试题


前言

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

如果按照顺序读取的文件非常多,那么嵌套的代码将会多的可怕,可读性差,难维护

一、promise说明概述

  1. Promise是一个构造函数(new Promise),它代表一个异步操作,可以解决回调地狱的问题

  2. 从语法上说,Promise 是一个对象,使用的使用需要 new

  3. Promise构造函数中有一个实参,这个实参是一个函数,这个实参函数会立即调用,new时会返回promise实例

  4. 实例身上有一个方法then(在原型上),then方法中有两个回调函数

  5. 第一个回调函数代表成功,这个成功的函数会赋值给resolve,第二个回调函数代表失败,这个失败的函数会赋值给reject

  6. 有时then()失败的回调函数可以不写,可以用catch捕获错误

  7. Promise.prototype有then方法 catch方法,还有finally方法

  8. 比传统的解决方案(回调函数和事件)更合理和更强大

  9. Promise可以理解为一个容器,里面可以编写异步程序的代码

  10. Promise是“承诺”的意思,实例中,它里面的异步操作就相当于一个承诺,而承诺就会有两种结果,要么完成了承诺的内容,要么失败

  11. 使用Promise,分为两大部分,首先是有一个承诺(异步操作),然后再兑现结果

二、使用promise分为两大部分

const fs = require('fs');
// promise 承诺

// 使用Promise分为两大部分

// 1. 定义一个承诺
let p = new Promise((resolve, reject) => {
    // resolve -- 解决,完成了; 是一个函数
    // reject  -- 拒绝,失败了; 是一个函数
    // 异步操作的代码,它就是一个承诺
    fs.readFile('./a.txt', 'utf-8', (err, data) => {
        if (err) {
            reject(err);
        } else {
            resolve(data.length);
        }
    });
});

// 2. 兑现承诺
// p.then(
//     (data) => {}, // 函数类似的参数,用于获取承诺成功后的数据
//     (err) => {} // 函数类型的参数,用于或承诺失败后的错误信息
// );
p.then(
    (data) => {
        console.log(data);
    },
    (err) => {
        console.log(err);
    }
);

三、promise的三种状态

  1. 最初状态:pending,等待中,此时promise的结果为 undefined;

  2. 当 resolve(value) 调用时,达到最终状态之一:fulfilled,(成功的)完成,此时可以获取结果value

  3. 当 reject(error) 调用时,达到最终状态之一:rejected,失败,此时可以获取错误信息 error

达到最终的 fulfilled 或 rejected 的时候,promise的状态就不会再改变了

四、同步和异步问题

new Promise是同步执行,获取结果时(调用 resolve 触发 then方法时)是异步的

console.log(1);

new Promise((resolve, reject) => {
  console.log(2);
  resolve();
  console.log(3);
}).then(res => {
  console.log(4);
})

console.log(5);

// 输出顺序: 1  2  3  5  4 ,因为只有 .then() 是异步的

五、then方法的链式调用

概述说明

前一个then里面返回的字符串,会被下一个then方法接收到。但是没有意义

但是前一个then里面返回的Promise对象,并且调用resolve的时候传递了数据,数据会被下一个then接收到

注意:前一个then里面如果没有调用resolve,则后续的then不会接收到任何值

实现原理

Promise 也还是使用回调函数,只是把回调封装在内部,一直通过 then 方法的链式调用,使得多层的回调嵌套看起来变成了同一层的,书写上以及理解上会更直观和简洁一些

封装按顺序异步读取文件的函数

//封装一个函数读取文件

import fs from 'fs'
function read(fpath) {
  let p = new Promise(function(resolve, reject) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
      if(err) return reject(err)
      resolve(dataStr)
    })
  })
  return p
}


read('./files/1.txt').then(function(res1) {
  console.log(res1)
  return read('./files/2.txt')
}).then(function(res2) {

  console.log(res2)
  return read('./files/3.txt')
}).then(function(res3) {

  console.log(res3)
}).catch(function(err){

  //读取错误
  console.log(err.message)
})

catch方法可以统一获取错误信息

六、promise的静态方法

Promise.all()

Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的.then操作(等待机制),数组中 Promise 实例的顺序,就是最终结果的顺序

//封装一个函数读取文件

import fs from 'fs'
function read(fpath) {
  let p = new Promise(function(resolve, reject) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
      if(err) return reject(err)
      resolve(dataStr)
    })
  })
  return p
}

let p1 = read('./files/1.txt')
let p2 = read('./files/2.txt')
let p3 = read('./files/3.txt')

// let promiseArr = [p1, p2, p3]
Promise.all([p1, p2, p3]).then(res => {
  console.log(res);
})

Promise.race()

Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一 步的.then 操作(赛跑机制),有一个promise异步操作执行完毕时,then方法中的结果时最先获取数据的结果

七、async/await 简化Promise异步操作

async/await概述说明

一直有人提出各种各样的方案,试图解决 异步操作,从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制

ES2017提供了async和await关键字。await和async关键词能够将异步请求的结果以返回值的方式返回给我们

  • async 用于修饰一个 function,如果一个函数声明前用了async,这个函数可以称为异步函数

    • async 修饰的函数,总是返回一个 Promise 对象

    • 没有return时,空promise没有太多实质意义

    • return一个非promise,将数据包装成了promise

    • return promise, 返回的就是该promise。

  • await 只能出现在 async 函数内

    • await 让 JS 引擎等待直到promise完成并返回结果

    • 语法:let value = await promise对象; // 要先等待promise对象执行完毕,才能得到结果

    • 由于await需要等待promise执行完毕,所以await会暂停函数的执行,但不会影响其他异步任务

  • 对于错误处理,可以选择在async函数后面使用 .catch() 或 在promise对象后使用 .catch()

简化代码

async function getFile(){
   const p1 = await read('./files/1.txt')
   const p2 = await read('./files/2.txt')
   const p3 = await read('./files/3.txt')

   console.log(p1,p2,p3);
}
getFile()

async/await的使用注意事项

① 如果在 function 中使用了 await,则 function 必须被 async 修饰

② 在 async 方法中,第一个 await 之前的代码会同步执行,await 之后的代码会异步执行

console.log('a');
async function getFile(){
   console.log("b");
   const p1 = await read('./files/1.txt')
   const p2 = await read('./files/2.txt')
   const p3 = await read('./files/3.txt')
   console.log("c");
   console.log(p1,p2,p3);
   console.log("d");
}
console.log("e");
getFile()
console.log("f");
//结果: a e b f c 111 222 333 d

八、宏任务和微任务

JavaScript 是一门单线程执行的编程语言。同一时间只能做一件事情

eventloop

为了防止某个耗时任务导致程序假死的问题,JavaScript 把待执行的任务分为了两类:

① 同步任务(synchronous)

  • 又叫做非耗时任务,指的是在主线程上排队执行的那些任务

  • 只有前一个任务执行完毕,才能执行后一个任务

② 异步任务(asynchronous)

  • 又叫做耗时任务,异步任务由 JavaScript 委托给宿主环境进行执行

  • 当异步任务执行完成后,会通知 JavaScript 主线程执行异步任务的回调函数

先执行同步任务,只有所有的同步任务执行完毕时,才执行执行异步任务

//代码
 console.log(1);
 setTimeout(function(){
     console.log(2);
 },1000)
 console.log(3);
//结果: 1 3 2

 for(var i = 0; i<5; i++){
     setTimeout(function(){
         console.log(i);
     },i*1000)
 }
//结果: 5个5  全局变量i=5

 for(let i = 0; i<5; i++){
     setTimeout(function(){
         console.log(i);
     },i*1000)
 }
//结果: 0 1 2 3 4    块级作用域

宏任务和微任务说明

① 宏任务(macrotask)

  • 异步 Ajax 请求、

  • setTimeout、setInterval、

  • 文件操作

  • 其它宏任务

② 微任务(microtask)

  • Promise.then、.catch 和 .finally

  • process.nextTick

  • 其它微任务

宏任务和微任务的执行顺序

先主线程 再异步任务,异步任务先微后宏(注意如果宏任务里面有微任务,这里的微任务不会在当前宏任务之前执行)

经典面试题

console.log(1)

setTimeout(function(){
    console.log(2)
    new Promise(function(resolve){
        console.log(3)
        resolve()
    }).then(function(){
        console.log(4)
    })
},1000)

new Promise(function(resolve){
    console.log(5)
    resolve()
}).then(function(){
    console.log(6)
})

setTimeout(function(){
    console.log(7)
    new Promise(function(resolve){
        console.log(8)
        resolve()
    }).then(function(){
        console.log(9)
    })
},500)

//结果:  1 5 6 7 8 9 2 3 4

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寒来暑往秋收冬藏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值