Nodejs环境下大家怎么做异步代码的?

Nodejs环境下大家怎么做异步代码的?

没有实际接触过大的nodejs工程代码,所以想看看大家平时都是怎么用的。

今天把一些基础的nodeschool.io的tutorial做了一下,异步相关的模式大概有四类,

  1. callback, 这个是最好理解的做法了,当一个event发生的时候(主要是io event),调用对应的callback去处理。最大的缺点是不直观,callabck hell难以维护,难以阅读。如果要combine多个io的结果,会很麻烦。
  2. async辅助的callback, 这种做法里,虽然还是callback的理念,但是通过async写把callback的依赖关系标准化,增加可读性。 试了一下tutorial里面的例子,代码还是难读。
  3. promise, 这个是我用的比较舒服的一种方法,我以前的很多project是java写就的,使用类似的类库(ListenableFuture)来处理异步依赖关系。
  4. Event Stream, 试了一下他的tutorial,整体的想法很好,有点类似golang的channel concept,跟python的generator的模式有点类似,不过还没有机会深入了解。如果一个逻辑同时依赖与两个或者多个IO输入,那么怎么处理这一类问题不是很清楚。

5 回复

Node.js 环境下大家怎么做异步代码的?

引言

在Node.js环境中,异步编程是一个核心概念,因为Node.js的主要优势之一就是其非阻塞I/O模型。然而,随着项目的复杂度增加,如何有效地管理这些异步操作成为了一个挑战。本文将介绍几种常见的异步处理方式,并提供相应的代码示例。

常见的异步处理模式

  1. 回调(Callback) 回调是最基础也是最直接的方式。当某个异步操作完成时,会调用相应的回调函数进行处理。

    const fs = require('fs');
    
    fs.readFile('example.txt', 'utf8', function(err, data) {
      if (err) throw err;
      console.log(data);
    });
    

    优点:简单易懂。 缺点:容易陷入回调地狱(Callback Hell),难以维护和阅读。

  2. async/await 使用asyncawait可以让异步代码看起来更像同步代码,提高了可读性和可维护性。

    const fs = require('fs').promises;
    
    async function readExampleFile() {
      try {
        const data = await fs.readFile('example.txt', 'utf8');
        console.log(data);
      } catch (err) {
        console.error(err);
      }
    }
    
    readExampleFile();
    

    优点:代码结构清晰,易于阅读。 缺点:需要Node.js版本支持。

  3. Promise Promise是一种处理异步操作的标准方式,可以用来避免回调地狱。

    const fs = require('fs').promises;
    
    fs.readFile('example.txt', 'utf8')
      .then(data => {
        console.log(data);
      })
      .catch(err => {
        console.error(err);
      });
    

    优点:结构清晰,易于组合多个异步操作。 缺点:对于复杂的错误处理可能需要额外的工作。

  4. 事件流(Event Streams) 事件流是一种基于事件驱动的设计模式,类似于Go语言中的通道(Channel)或Python中的生成器(Generator)。

    const { Readable } = require('stream');
    
    const readableStream = new Readable({
      read() {}
    });
    
    readableStream.on('data', (chunk) => {
      console.log(chunk.toString());
    });
    
    readableStream.push('Hello ');
    readableStream.push('World');
    readableStream.push(null); // end the stream
    

    优点:适合处理连续的数据流。 缺点:对于初学者来说可能较难理解。

总结

每种方法都有其适用场景,选择合适的异步处理方式可以显著提高代码质量和开发效率。对于初学者来说,推荐从简单的回调开始,逐渐过渡到async/await和Promise,以便更好地理解和应用这些技术。


楼主的标题,看了半天没弄明白啥意思

刚才粗粗简单翻了一下cnodejs自己的源代码,还是以callback为主。 javascript代码写起来比较快,简洁,不过感觉可读性和严谨程度比java系的代码要差一些。工程一旦上规模,共同开发的人多了以后,维护难读可能会加大。

归递调用流 cb + apply + call

在Node.js环境下处理异步代码主要有以下几种方式:

  1. 回调函数 (Callbacks): 回调函数是最基本的方式,但容易形成“回调地狱”(Callback Hell)。

    fs.readFile('file1.txt', (err, data) => {
        if (err) throw err;
        console.log(data);
        fs.readFile('file2.txt', (err, data) => {
            if (err) throw err;
            console.log(data);
        });
    });
    
  2. asyncawait: 基于Promise,更易于理解和维护。

    const fs = require('fs').promises;
    
    async function readFiles() {
        try {
            const data1 = await fs.readFile('file1.txt');
            console.log(data1.toString());
            const data2 = await fs.readFile('file2.txt');
            console.log(data2.toString());
        } catch (err) {
            console.error(err);
        }
    }
    
    readFiles();
    
  3. Promises: 使用.then().catch() 处理异步操作。

    const fs = require('fs').promises;
    
    fs.readFile('file1.txt')
        .then(data => {
            console.log(data.toString());
            return fs.readFile('file2.txt');
        })
        .then(data => {
            console.log(data.toString());
        })
        .catch(err => {
            console.error(err);
        });
    
  4. 流(Streams): 适用于大数据量处理,如文件读写、网络传输等。

    const fs = require('fs');
    
    const readStream = fs.createReadStream('largeFile.txt');
    const writeStream = fs.createWriteStream('output.txt');
    
    readStream.pipe(writeStream);
    
  5. 事件驱动编程(Event-Driven Programming): 使用EventEmitter 类处理异步事件。

    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();
    
    myEmitter.on('dataReady', data => {
        console.log(data);
    });
    
    myEmitter.emit('dataReady', 'Data is ready!');
    

总结

在Node.js中,使用asyncawait是最推荐的方法,因为它既保留了Promise的优点,又避免了回调地狱的困扰。对于数据流处理,使用流的方式也非常高效。

回到顶部