开发者

How do I avoid deeply nested code in node.js?

开发者 https://www.devze.com 2023-02-08 20:53 出处:网络
In node.js, it being event-driven, all I/O is done via callbacks. So I end up writing code that looks like this:

In node.js, it being event-driven, all I/O is done via callbacks. So I end up writing code that looks like this:

app.get('/test', function (req, res) {
  http.get('some/place', function (req1, res1) {
    if (res1.statusCode == 200) {
      res1.on('data', function (d开发者_运维问答ata) {
        http.get('other/place?q=' + data, function (req2, res2) {
          if (res2.statusCode == 200) {
            res2.on('data', function (data) {
              db.query(data).on('data', function (rows) {
                res.writeHead(200)
                res.end(JSON.stringify(rows))
              })
            })
          }
        })
      })
    }
  })
})

And that doesn't even include error handling.

What can I do to unwind this mess?


You could use async module to avoid this.


Don't use anonymous functions.

EDIT

Your code isn't even valid. You aren't closing most of your function calls.

If you switched to named functions it would look something like this: Updated to reflected comment about global namespace

(function () {
    app.get('/test', f0)

    function f0(req, res) {
      http.get('some/place', f1)
    }

    function f1(req1, res1) {
        if (res1.statusCode == 200) {
          res1.on('data', f2)
        }
     }
    function f2(data) {
        http.get('other/place?q=' + data, f3)
    }
    function f3(req2, res2) {
      if (res2.statusCode == 200) {
        res2.on('data', f4)
      }
    }

    function f4(data) {
          db.query(data).on('data', f5)
        }

    function f5(rows) {
        res.writeHead(200)
        res.end(JSON.stringify(rows))
    }
})()


I wrote a library based on node-seq, which looks like this:

app.get('/test', function (req, res) {
  Seq()
    .seq(function () {
      http.get('some/place', this.next)
    })
    .seq(function (req1, res1) {
      if (res1.statusCode == 200) {
        res1.on('data', this.next)
      }
    })
    .seq(function (data) {
      http.get('other/place?q=' + data, this.next)
    })
    .seq(function (req2, res2) {
      if (res2.statusCode == 200) {
        res2.on('data', this.next)
      }
    })
    .seq(function (data) {
      db.query(data).on('data', this.next)
    })
    .seq(function (rows) {
      res.writeHead(200)
      res.end(JSON.stringify(rows))
    })
})

The code is here.

Also, there's a lengthy discussion on the nodejs mailing list about this issue.

Step is another library for doing this stuff.


Please have a look at Streamline; it is a JavaScript preprocessor that allows you to write simple 'streamlined' code and transforms it to callback-heavy code.


Another (and perhaps better) way to clean up this kind of thing is to use EventEmitters rather than callbacks. Here's an example showing several EventEmitters in use:

    var events = require('events'),
    util = require('util');

    var Search = function () {
    "use strict";

    var search,
        requestPageData,
        makeReturnObject,
        sendResults,

        emptyObj = {};

    events.EventEmitter.call(this);

    search = function (query) {
        this.emit("requestPageData", query);
    };

    requestPageData = function (query) {
        var resultsArray = [];

        // some logic

        if (.....some condition....) {
            this.emit("makeReturnObject", resultsArray);
        } else {
            this.emit("sendResults", emptyObj);
        }
    };

    makeReturnObject = function (resultsArray) {
        var resultsObj = {};

        if (magnetArray) {

            // some logic

            this.emit("sendResults", resultsObj);
        } else {
            this.emit("sendResults", emptyObj);
        }
    };

    sendResults = function (obj) {
        // finally, do whatever it is you want to do with obj
    };

    this.on("requestPageData", requestPageData);

    this.on("makeReturnObject", makeReturnObject);

    this.on("sendResults", sendResults);

    this.search = search;

};

util.inherits(Search, events.EventEmitter);
module.exports = new Search();


You can use promises. Check this out https://github.com/kriskowal/q

0

精彩评论

暂无评论...
验证码 换一张
取 消