1

node.jsのコールバックと非同期にすることが理にかなっているのはいつかと自問しています。I / O、データベース、その他すべてのコードをブロックしたり、コードの残りの部分で作業したりするときに便利ですか?

たとえば、ボードゲームの「レイアウト」を入手しました。指定されたjsonレイアウトでボードインスタンスを作成します。I / O(jsonレイアウトファイルの読み取り)に非同期を使用するのは理にかなっていると理解しています。これはブロックされるためです。たとえば、foreachループではどうでしょうか。非同期にする必要がありますか?基礎となるlibuvは、これから何らかの形で利益を得ていますか?

非同期libを使用したバージョンは次のとおりです。

/*jshint node: true, strict: true, globalstrict: true*/
"use strict";

// Imports
var fs = require('fs');
var async = require('async');
var Figure = require('../models/figure.js');
var Field = require('../models/field.js');
var Board = require('../models/board.js');

/**
 * @param {Board} board
 * @param {Array} template
 * @param {string} owner
 * @param {function(Error)} callback
 */
var createFigures = function (board, template, owner, callback) {
    async.forEach(template, function (data, done) {
        var figure = new Figure(owner, data.kind);
        board.setFigure(data.x, data.y, figure);
        done();
    }, callback);
};

/**
 * @param {Board} board
 * @param {Array} fields
 */
var createFields = function (board, fields, callback) {
    async.series([
        function(done) {
            for (var x = 0; x < board.getSize().x; x++) {
                for (var y = 0; y < board.getSize().y; y++) {
                    var field = new Field(true, false);
                    board.setField(x, y, field);
                }
            }
            done();
        }, function(done) {
            async.forEach(fields, function(data, iteratDone) {
                var field = new Field(data.passable, data.corner);
                board.setField(data.x, data.y, field);
                iteratDone();
            });
            done();
        }
    ], callback);
};

/**
 * @param {{
 *  ....
 */
var build = function (layoutObj, callback) {
    var board = new Board(layoutObj.name, layoutObj.size.x, layoutObj.size.y);

    async.parallel([
        function (done) {
            createFigures(board, layoutObj.figures.white, Figure.owners.white, done);
        },
        function (done) {
            createFigures(board, layoutObj.figures.black, Figure.owners.black, done);
        },
        function (done) {
            createFields(board, layoutObj.fields, done);
        }
    ],
        function (err) {
            callback(err, board);
        }
    );
};

/**
 * @param string layoutPath
 * @param {function(Error, )} callback
 * @return {Board}
 */
var generateBoardWithLayout = function (layoutPath, callback) {
    async.waterfall([
        function(done) {
            fs.stat(layoutPath, function(err, stats) {
               done(null, stats);
            });
        }, function(stats, done) {
            if (stats.isFile()) {
                var jsonData = '';
                fs.readFile(layoutPath, function(err, data) {
                    jsonData += data;
                    done(null, jsonData);
                });
            } else {
                done(new Error("There is no '" + layoutPath + "'"));
            }
        }
    ], function(err, jsonData) {
        build(JSON.parse(jsonData), callback);
    });

};

module.exports.build = build;
module.exports.generateBoardWithLayout = generateBoardWithLayout;

そしてそれは非同期リンクのないバージョンです

/*jshint node: true, strict: true, globalstrict: true*/
"use strict";

// Imports
var Figure = require('../models/figure.js');
var Field = require('../models/field.js');
var Board = require('../models/board.js');

/**
 * @constructor
 */
function Layouter() {

}

Layouter.generateBoardWithLayout = function(layoutPath) {
    var fs = require('fs');

    var jsonData = fs.readFileSync(layoutPath);
    if (!jsonData) {
        throw new Error("There is no '" + layoutPath + "'");
    }

    return new Layouter().build(JSON.parse(jsonData));
};

Layouter.prototype = {

    /**
     * @param {{
     *     ....
     */
    build: function (layoutObj) {
        var board = new Board(layoutObj.name, layoutObj.size.x, layoutObj.size.y);

        this.createFigures_(board, layoutObj.figures.white, Figure.owners.white);
        this.createFigures_(board, layoutObj.figures.black, Figure.owners.black);
        this.createFields_(board, layoutObj.fields);

        return board;
    },

    /**
     * @param {Board} board
     * @param {Array} template
     * @param {string} owner
     * @private
     */
    createFigures_: function (board, template, owner) {
        template.forEach(function (data) {
            var figure = new Figure(owner, data.kind);
            board.setFigure(data.x, data.y, figure);
        });
    },

    /**
     * @param {Board} board
     * @param {Array} fields
     * @private
     */
    createFields_: function (board, fields) {
        for (var x = 0; x < board.getSize().x; x++) {
            for (var y = 0; y < board.getSize().y; y++) {
                var field = new Field(true, false);
                board.setField(x, y, field);
            }
        }

        fields.forEach(function (data) {
            var field = new Field(data.passable, data.corner);
            board.setField(data.x, data.y, field);
        });
    }

};

module.exports = Layouter;
module.exports.generateBoardWithLayout = Layouter.generateBoardWithLayout;

御時間ありがとうございます!

ご挨拶、マーカス

4

2 に答える 2

0

I / Oを実行せずに新しいオブジェクトインスタンスを作成するように見えます。この場合、uはコードを不必要に複雑にしているため、見苦しいです。プログラムを続行できるのは最後のコールバック関数のみです。これにより、フロー全体が1つの大きな非同期呼び出しに制限されます。

通常、プログラムフローは、コード内で最初に実行する前の非同期コールバックに依存するべきではありません

createFigure();  
createField();

どちらも単一の非同期呼び出しです。createField内の何かが最初に実行されるcreateFigureに依存している場合、この場合の動作は未定義です。通常、ブロッキング操作を行っている場合を除き、非同期を使用しないでください

于 2012-08-29T17:06:58.410 に答える
0

Node.jsの非同期性の背後にあるアイデアを見逃していると思います。これは、asyncパッケージ(Nodeで使用できるnpmパッケージであり、Nodeの内部パッケージではない)を使用することではなく、非同期で外部プロセスを処理することです。たとえば、データベースにクエリを実行すると、結果を待っている間に多くのことを実行する可能性があります。それが取引です。

コードが外部プロセスをクエリしないが、それがプレーンなJavaScriptである場合、単一のプロセスでは非同期性の恩恵を直接受けることはできません(Node.jsはシングルスレッドです)。ただし、一部の作業を別のプロセスに委任し、それと通信します(child_process.forkを参照)。

于 2012-08-30T14:36:36.993 に答える