node.js的新手,我不确定我是否正确这样做

时间:2013-09-09 05:12:12

标签: node.js

所以,代码可以工作,但是缩进级别是疯了......对于节点中的所有回调,我应该如何编码?

"use strict";

var crypto = require('crypto'),
    fs     = require('fs'),
    mmm    = require('mmmagic'),
    Magic  = require('mmmagic').Magic,
    path   = require('path');

console.log('Init controller: ' + path.basename(__filename));

exports.help = function () {
    var help;

    help  = "POST http://server/images\n";
    help += "    Upload image for storage.\n";
    help += "    <image> - The image file to upload\n";
    help += "    <title> - The title of the image, no more than 50 characters\n";
    help += "    <desc>  - The description of the image, no more than 1024 characters\n";

    return help;
}

exports.post = function (req, res) {
    var image = req.files.image;
    if (typeof(image) == 'undefined') {
        res.status(400).send("{error:'Upload error'}");
        return;
    }

    var magic = new Magic(mmm.MAGIC_MIME_TYPE);
    magic.detectFile(image.path, function(err, result) {
        if (err) {
            res.status(400).send("{error:'Upload mime error'}");
        } else {
            var mime = result.toLowerCase().split('/');

            if (mime[0] != 'image') {
                res.status(400).send("{error:'Upload not an image', mime: '" + result + "'}");
            } else {
                // Read the image file
                fs.readFile(image.path, function (err, data) {
                    if (err) {
                        res.status(400).send("{error:'Upload read error'}");
                    } else {
                        var hash = crypto.createHash('md5').update(data).digest("hex");
                        req.app.models.image.count({'hash': hash}, function (err, count) {
                            if (err) {
                                res.status(400).send("{error:'ORM Error: '" + JSON.stringify(err) + "'}");
                            } else {
                                if (count > 0) {
                                    res.status(400).send("{error:'Image already exists'}");
                                } else {
                                    var hash = crypto.createHash('md5').update(data).digest("hex");
                                    var newPath = path.join(req.app.tempDir, hash);
                                    fs.writeFile(newPath, data, function (err) {
                                        if (err) {
                                            res.status(400).send("{error:'Upload write error'}");
                                        } else {
                                            // Save the image
                                            req.app.models.image.create([{
                                                'hash'      : hash,
                                                'mime'      : mime,
                                                title       : '',
                                                description : ''
                                            }], function(err, images) {
                                                if (err) {
                                                    fs.unlink(newPath);
                                                    res.status(400).send("{error:'" + err.message + "'}");
                                                } else {
                                                    res.status(200).send("{id:'" + images[0].id + "}");
                                                }
                                            });
                                        }
                                    });
                                }
                            }
                        });
                    }
                });
            }
        }
    });
}

6 个答案:

答案 0 :(得分:5)

http://callbackhell.com/提供了适应异步编程的指南。

评论中的一些后续行动:

  • 如果使异步代码看起来像自上而下的同步代码,那么有Node FibersIced CoffeeScript这样的项目会吸引你,并且被这种错觉误导并不会让你非常紧张。但是,我强烈建议使用常规的javascript和异步编程与回调(而不是承诺),直到灯泡亮起,然后再探索解决方案,找出你真正不理解的“问题”。
  • 异步代码是在操作系统完成I / O时执行的一堆代码。这就是为什么它不能自上而下读 - 因为它不会自上而下执行。它会在IO完成后执行,这就是它扩展它的方式。
  • 不要被初学者片段误导。在决定异步代码不可读之前,请先查看TJ Holowaychuk等大师的代码。回调地狱是一个初学现象。这是非常普遍的。几乎每个人都将它作为一个阶段来完成,但是要超越它并不是特别困难,特别是考虑到掌握多线程锁定和信号量及其调试的替代方案。读取良好的异步代码通常只是直接设计得更好的代码。但是,是的,它缺乏同步代码的自上而下的有序性,这意味着更多的源头跳跃。

答案 1 :(得分:2)

<shamelessPlug>

我经历了回调意大利面的过程 - &gt;承诺意大利面 - &gt;写了我自己的承诺管理库

That library is available here

... and this describes the above process in a bit more detail

</shamelessPlug>

在任何情况下,一般的答案都是肯定的 - 你最终会收到一堆回调。为了阻止这种情况发生,最好通过回调管理系统或承诺服务。

哪种方法最好?这真的取决于你,你喜欢什么。

答案 2 :(得分:1)

我发现承诺的概念对此有很大帮助。 JavaScript中有许多promises实现,但想法是一样的。你可以从这个开始:

https://github.com/kriszyp/node-promise

答案 3 :(得分:1)

来一个人。你真的认为你需要一个库吗?你可以用纯JavaScript来处理它。这是重写的代码:

var response = null,
    request = null;
var fileDetected = function(err, result) {
    if (err) {
        response.status(400).send("{error:'Upload mime error'}");
    } else {
        var mime = result.toLowerCase().split('/');
        if (mime[0] != 'image') {
            response.status(400).send("{error:'Upload not an image', mime: '" + result + "'}");
        } else {
            // Read the image file
            fs.readFile(image.path, onReadFile);
        }
    }
}
var onReadFile = function(err, data) {
    if (err) {
        response.status(400).send("{error:'Upload read error'}");
    } else {
        var hash = crypto.createHash('md5').update(data).digest("hex");
        request.app.models.image.count({'hash': hash}, onImageCount);
    }
}
var onImageCount = function(err, count) {
    if (err) {
        response.status(400).send("{error:'ORM Error: '" + JSON.stringify(err) + "'}");
    } else {
        if (count > 0) {
            response.status(400).send("{error:'Image already exists'}");
        } else {
            var hash = crypto.createHash('md5').update(data).digest("hex");
            var newPath = path.join(request.app.tempDir, hash);
            fs.writeFile(newPath, data, onFileWrite);
        }
    }
}
var onFileWrite = function(err) {
    if (err) {
        response.status(400).send("{error:'Upload write error'}");
    } else {
        // Save the image
        request.app.models.image.create([{
            'hash'      : hash,
            'mime'      : mime,
            title       : '',
            description : ''
        }], function(err, images) {
            if (err) {
                fs.unlink(newPath);
                response.status(400).send("{error:'" + err.message + "'}");
            } else {
                response.status(200).send("{id:'" + images[0].id + "}");
            }
        });
    }
}

exports.post = function (req, res) {
    request = req;
    response = res;
    var image = request.files.image;
    if (typeof(image) == 'undefined') {
        response.status(400).send("{error:'Upload error'}");
        return;
    }
    var magic = new Magic(mmm.MAGIC_MIME_TYPE);
    magic.detectFile(image.path, fileDetected);
}

好的部分是,通过将不同功能中的所有内容分开,您实际上将逻辑拆分为块。新创建的函数的名称说明了块的用途。

答案 4 :(得分:0)

如果您需要评论某些内容是“加载图片”或“保存图片”,将其提取到单独的函数中将有助于提高可读性,降低缩进级别,并消除对评论的需求。

即。而不是写作

// ... 
      petAHorse(function(horsesResponse) {
        // ...
      })
// ... 

你可以写

function horsePettedHandler(horsesResponse) {
  // ...
}

// ... 
      petAHorse(horsePettedHandler);
// ...

答案 5 :(得分:0)

我更愿意使用node-sync lib而不是承诺。因为它允许一个伟大的事情:你不必为promises包装async libs函数,你可以使用特殊的语法。像这样:

var result = thirdPartyLibAsyncFunction.sync(null, 2, 3);

它以相同的方式使用您自己的代码。