nodejs学习重点之Promise和asnyc/await

本文探讨了JavaScript中的异步IO重要性,如何避免回调地狱,以及Promise和async/await的使用。Promise用于改善异步代码的可读性,而async/await则提供了更接近同步编程的体验,简化了错误处理。通过实例展示了如何使用这两个特性进行文件系统操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道,如果我们以同步的方式编写耗时的代码,那么就会阻塞JS的单线程,造成CPU一直等待IO完成才去执行后面的代码;而CPU的执行速度是远远大于硬盘IO速度的,这样等待只会造成资源的浪费。异步IO就是为了解决这个问题的,异步能尽可能不让CPU闲着,它不会在那等着IO完成;而是传递给底层的事件循环一个函数,自己去执行下面的代码。等磁盘IO完成后,函数就会被执行来作为通知。

虽然异步和回调的编程方式能充分利用CPU,但是当代码逻辑变的越来越复杂后,新的问题出现了。请尝试用异步的方式编写以下逻辑代码:

先判断一个文件是文件还是目录,如果是目录就读取这个目录下的文件,找出结尾是txt的文件,然后获取它的文件大小。

恭喜你,当你完成上面的任务时,你已经进入了终极关卡:Callback hell回调地域!

就是每一个逻辑都要写一个回调, 导致回调地狱

 

为了解决Callback hell的问题,Promiseasync/await诞生。

  • promise的作用是对异步回调代码包装一下,把原来的一个回调函数拆成2个回调函数,这样的好处是可读性更好。语法如下:

    语法注意:Promise内部的resolve和reject方法只能调用一次,调用了这个就不能再调用了那个;如果调用,则无效。

  // 一段逻辑:
  // 先判断一个文件是文件还是目录,如果是目录就读取这个目录下的文件列表,
  // 找出结尾是txt的文件,然后获取它的文件大小。
  let fs = require("fs");
  let path = require('path');
  let util = require('util');
  
  function withoutPromise() {
      let target = "test";
      fs.stat(target, (err, stat)=>{
          if(err){
              throw err;
          }
          // 如果是文件夹
          if(stat.isDirectory()){
              fs.readdir(target, (err, files)=>{
                  // 遍历files
                  files.forEach( f =>{
                      if(path.extname(f) === '.txt'){
                          fs.stat(path.join(target, f), (err, stat)=>{
                              console.log(f+ " : "+stat.size);
                          });
                      }
                  } );
              });
          }
      });
  }
  
  
  
  // 用promise和async/await的风格来改下上面的逻辑
  async function withPromise() {
      let target = "test";
      //将fs.stat转为一个可以返回Promise对象的方法
      let pstat = util.promisify(fs.stat);
      let stat = await pstat(target);
      // 如果是文件夹
      if(stat.isDirectory()){
          //将fs.readdir转为一个可以返回Promise对象的方法
          let preaddir = util.promisify(fs.readdir)
          //文件夹得到了一个数据保存到files里
          let files = await preaddir(target)
          files.forEach( async (f) => {
              if(path.extname(f) === '.txt'){
                  let stat = await pstat(path.join(target, f));
                  console.log(stat.size);
  
                  // fs.stat(path.join(target, f), (err, stat)=>{
                  //     console.log(f+ " : "+stat.size);
                  // });
              }
          });
      }
  }
  
  withPromise();

async/await的作用是直接将Promise异步代码变为同步的写法,注意,代码仍然是异步的。这项革新,具有革命性的意义。

语法要求:

  • await只能用在async修饰的方法中,但是有async不要求一定有await

  • await后面只能跟async方法和promise

  • 实际上很多的库都以及封装好了promise库, 直接await就可以了

假设拥有了一个promise对象,现在使用async/await可以这样写:

async function asyncDemo() {
    try {
        // 当promise的then方法执行的时候
        let text = await promise   //重点:  await的底层是异步执行的
        // 当你用promise包装了所有的异步回调代码后,就可以一直await,真正意义实现了以同步的方式写异步代码
        console.log('异步道明执行');
    }catch (e){
        // 捕获到promise的catch方法的异常
        console.log(e);
    }
}
asyncDemo()
console.log('我是同步代码');

使用nodejs中文网里的SDK里的util工具类, util.promisify这个方法可以方便的把所有的异步回调都转成promise, 这样就可以

通过promise把所有的异步操作包装起来, 用await语法来调用promise, 用try/catch捕获promise内部的异常

异步代码的终极写法:

  1. 先使用promise包装异步回调代码,可使用node提供的util.promisify方法;

  2. 使用async/await编写异步代码。

  3. 简单点说就是promise包装, async来调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值