Асинхронные обратные вызовы, и закрытие


После того, как провел месяц или два, пытаясь узнать JavaScript, особенно функциональное программирование, асинхронный, и закрытие, я, наконец, получить его. Но я не знаю, если я пишу элегантный код... в частности, я не уверен, если я создаю слишком много закрытий, потому что я полностью не понять, когда контексты остаются и когда они помечен для сборки мусора.

Вы можете видеть пример, который я использую node.js -- по сути, это просто кусок тестового кода, который подключается к базе данных, получает 20 000 записей асинхронно с индивидуальными выбрать запросы (я просто делал некоторые профилирования, не волнуйтесь), и манипулирует данными. В конце концов, он говорит мне, как долго он взял и закрывает соединение с MySQL.

Для того, чтобы получить окончательную метку и закрыть соединение, мне нужно что-то вроде асинхронного библиотеке, чтобы отслеживать все различные асинхронные функции, которые породили. Он принимает все мои запросы как массив функций (через завод, который называется makeQuery()) и затем запускает функцию обратного вызова, чтобы сделать уборку.

Вопросы:

  1. Я создаю огромное количество контекстов, создавая и возвращая функцию doQuery() , который использует аргумент ИД в makeQuery() функция, причинив тем самым 20,000 контекстах, сохранится до асинхронности.параллельные() выполняется?

  2. Это заводская функция makeQuery() хороший и аккуратный способ, чтобы создать этот массив doQuery() функции? Можете ли вы предложить какой-нибудь лучший способ сделать это?

var mysql = require('mysql');
var radix64 = require('./lib/radix64');
var async = require('async');

var client = mysql.createClient({user: 'root', password: '12345678'});
client.query('USE nodetest');

var startTime = (new Date()).getTime(); // poor man's profiling
var queries = []; // this will be fed to async.parallel() later

var makeQuery = function makeQuery (id) { // factory function to create the queries
    return function doQuery (cb) {
        client.query('SELECT * FROM urls WHERE id='+id,
            function logResults (e, results, fields) {
                results = results[0];
                results.key = radix64.fromNumber(results.id); // yep, I'm converting the
                                                              // number into base-64 notation
                cb(); // if I wanted to do something useful at the end, I would have
                      // called cb(results) instead, which compiles an array of results
                      // to be accessed by the final callback
            }
        );
    };
};

for (i = 1001; i <= 20000; i ++) { // build the list of tasks to be done in parallel
    queries.push(makeQuery(i));
}

// run those tasks
async.parallel(queries, function finished () { // clean up and get the elapsed time
    console.log('done');
    client.end();
    console.log(((new Date()).getTime() - startTime) / 1000);
});

Для тех из вас знакомы с асинхронными, это пользовательский модуль, построенный для node.js а браузер. Каждая функция в массиве, который передается в асинхронности.параллельные() обязан принять обратного вызова, а затем запустить, что обратного вызова, как только это сделано, для того, чтобы асинхронный.параллельные() знаю, что это сделал.



3640
4
задан 16 ноября 2011 в 04:11 Источник Поделиться
Комментарии
2 ответа

ВАР makeQuery = makeQuery функция (идентификатор) {

Нет необходимости, чтобы сделать makeQuery локальную переменную, просто использовать функцию декларации.

results = results[0];
results.key = radix64.fromNumber(results.id);

Ваш просто увеличивает объект, вы не делаете ничего с ним.

Другой тогда, что, не создавая новых функций в цикле, используя функцию-конструктор. Это правильно.

Ваш работает все 19000 запросов параллельно, а потом в водопад, который также является правильным.

Редактировать:

Вопрос 1:

Вам нужно создать 20000 контекстах. Потому что есть 20000 значений я. Беспокоясь о том, что 20000 функций-это микро-оптимизации. двигатель V8 оптимизирует ад из вашего кода.

Он фактически разделяет свои функции в скрытый класс отдельно от закрытия контексте, и в моей памяти вы просто 20000 значений я и одно значение функции.

Просто напоминаю вам о правиле 1.


Никогда не стоит недооценивать В8

Вопрос 2:

makeQuery как фабрика является правильным рисунком, чтобы использовать.

Только другие оптимизации вы можете сделать, это написать запрос реальной SQL, а затем 20000 придурки. Но я буду игнорировать это, потому что это пример муляж.

2
ответ дан 16 ноября 2011 в 04:11 Источник Поделиться

Если вы сомневаетесь, идти с ограничением контексте закрытия в области видимости функции:

function makeLog(cb) {
return function (e, results, fields) { // logResults
results = results[0];
results.key = radix64.fromNumber(results.id); // yep, I'm converting the
// number into base-64 notation
cb(); // if I wanted to do something useful at the end, I would have
// called cb(results) instead, which compiles an array of results
// to be accessed by the final callback
};
}

function makeQuery(id, aClient) { // factory function to create the queries
return function (cb) { // doQuery
aClient.query('SELECT * FROM urls WHERE id=' + id, makeLog(cb));
};
}

for (i = 1001; i <= 20000; i++) { // build the list of tasks to be done in parallel
queries.push(makeQuery(i, client));
}

В противном случае, вы можете также избавиться от заводов в целом:

for (i = 1001; i <= 20000; i++) { // build the list of tasks to be done in parallel
queries.push(function (cb) { // doQuery
client.query('SELECT * FROM urls WHERE id=' + i,
function (e, results, fields) { // logResults
results = results[0];
results.key = radix64.fromNumber(results.id); // yep, I'm converting the
// number into base-64 notation
cb(); // if I wanted to do something useful at the end, I would have
// called cb(results) instead, which compiles an array of results
// to be accessed by the final callback
});
});
}

1
ответ дан 12 сентября 2012 в 05:09 Источник Поделиться