Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.14.83.223] |
|
Сообщ.
#1
,
|
|
|
Написал свою упрощенную версию async.series, но не работает
function foreach(arrayFuncs, iterFunc, callback) { var done = false, isRunning = false, i = 0, iterator = arrayFuncs.values(); while (!isRunning && !done) { var item = iterator.next(); var elem = null; if (!item.done) { elem = {task: item.value, key: i++}; } if (elem === null) { done = true; if (isRunning) callback(null); return; } isRunning = true; iterFunc(elem.task, elem.key, err => { isRunning = false; if (err) { done = true; callback(err); } }); } } function series(tasks, callback) { var results = []; foreach(tasks, function (task, key, callback) { task((err, result) => { results[key] = result; callback(err); }); }, function (err) { callback(err, results); } ); } // test series([ cb => setTimeout(() => cb(null, 'task 1'), 1000), cb => setTimeout(() => cb(null, 'task 2'), 1000) ], (err, results) => { if (err) return console.log(err); console.log(results); }); console.log('test series'); Где я накосячил? |
Сообщ.
#2
,
|
|
|
надо спросить у масты, он ответит.
|
Сообщ.
#3
,
|
|
|
Сам все порешал!
Через цикл чет я завис, потом решу для практики. А пока рекурсивное решение, рекурсивно мыслить проще да и значительно сократилась сама функция function foreach(arrayFuncs, iterFunc, callback) { var iterator = arrayFuncs.values(); var key = 0; function next() { var item = iterator.next(); if (item.done) return callback(null); iterFunc(item.value, key++, err => { if (err) return callback(err); next(); }); } next(); } function series(tasks, callback) { var results = []; foreach(tasks, function (task, key, callback) { task((err, result) => { results[key] = result; callback(err); }); }, function (err) { callback(err, results); } ); } // test series([ cb => setTimeout(() => {console.log('1'); cb(null, 'task 1')}, 1000), cb => setTimeout(() => {console.log('2'); cb(null, 'task 2')}, 1000), cb => setTimeout(() => {console.log('3'); cb(null, 'task 3')}, 1000) ], (err, results) => { if (err) return console.log(err); console.log(results); }); console.log('test series'); // test series // 1 // 2 // 3 // [ 'task 1', 'task 2', 'task 3' ] |
Сообщ.
#4
,
|
|
|
Теперь надо реализовать async.parallel и async.waterfall.
Новичок! Я тебя вижу не прячься! - Маста а может сначало объясните как реализована series? |
Сообщ.
#5
,
|
|
|
Ок Маста сам все порешал вот накалбасил по аналогии
function foreach(arrayFuncs, iterFunc, callback) { var done = false, running = 0, iterator = arrayFuncs.values(), key = 0; while (!done) { var item = iterator.next(); if (item.done) { done = true; if (running <= 0) callback(null); return; } running++; iterFunc(item.value, key++, err => { running--; if (err) { done = true; callback(err); } else if (running <= 0) { callback(null); } }); } } function parallel(tasks, callback) { var results = []; foreach(tasks, function (task, key, callback) { task((err, result) => { results[key] = result; callback(err); }); }, function (err) { callback(err, results); } ); } //test parallel parallel([ cb => {console.log('1'); setTimeout(() => cb(null, 'task 1'), 2000)}, cb => {console.log('2'); setTimeout(() => cb(new Error('Error!!!'), 'task 2'), 2000)}, cb => {console.log('3'); setTimeout(() => cb(null, 'task 3'), 2000)} ], (err, results) => { if (err) return console.log(err); console.log(results); }); console.log('test parallel'); /* 1 2 3 test parallel Error: Error!!! at Timeout.setTimeout [as _onTimeout] (/Users/cfon/workspace/JavaScript/examples/async-parallel.js:49:50) at ontimeout (timers.js:436:11) at tryOnTimeout (timers.js:300:5) at listOnTimeout (timers.js:263:5) at Timer.processTimers (timers.js:223:10) [ 'task 1', 'task 2', 'task 3' ] */ Код прекрасно работает все выводит, но тут что-то не так поскольку результат всеравно возвращается даже если возникает ощибка Где я накосячил? Кстати сама функция parallel один в один series т.е. она не изменилась! А все модификации каснулись функции foreach. |
Сообщ.
#6
,
|
|
|
Новичок! Апладирую стоя
Я проверил твой код и должен сказать, что ситуация тут весьма запутана! Чтобы разобраться в этих хитросплетениях колбэк вызовов требуется не малая интелектуальная нагрузка Так что пока я могу предложить тебе следущий кастыль, мы можем прервать цепочку колбэков используя следущий трюк: function parallel(tasks, callback) { var results = []; callback = once(callback); //<-- переопределяем колбэк на однократный запуск foreach(tasks, function (task, key, callback) { task((err, result) => { results[key] = result; callback(err); }); }, function (err) { callback(err, results); } ); } function once(cb) { return function (...args) { if (cb === null) return; var callback = cb; cb = null; callback(...args); }; } Теперь в случае ошибки наш колбэк вызовется только один раз. - Вау Маста! Это работает! Но как ты понимаешь таски, которые были запущены они все отрабатывают, тут просто не вызывается конечный колбэк функции parallel в случае ошибки и как следствие результат не выводится на экран. |
Сообщ.
#7
,
|
|
|
А вот другое решение, поскольку именно переменная running используется для контроля запуска финального колбэка, все что нам надо при ошибке сделать ее значение например undefined
function foreach(arrayFuncs, iterFunc, callback) { var done = false, running = 0, iterator = arrayFuncs.values(), key = 0; while (!done) { var item = iterator.next(); if (item.done) { done = true; if (running <= 0) callback(null); break; } running++; iterFunc(item.value, key++, err => { running--; if (err) { running = undefined; //<-- тадам! callback(err); } else if (running <= 0) { callback(null); } }); } } |
Сообщ.
#8
,
|
|
|
Новая версия функции series
Убрал ненужную сложность кода, теперь проще понять как все работает: function series(tasks, callback) { const results = []; var iterator = tasks.values(); var key = 0; function next() { var item = iterator.next(); if (item.done) return callback(null, results); item.value((err, result) => { results[key++] = result; if (err) return callback(err); next(); }); } next(); }; Новичок переделай async.parallel и async.waterfall. |
Сообщ.
#9
,
|
|
|
Masta, ты молодец.
Юзаешь эту гребанную технологию JS. Ждем когда она сойдет на нет. |
Сообщ.
#10
,
|
|
|
Цитата nash @ Masta, ты молодец. Юзаешь эту гребанную технологию JS. Ждем когда она сойдет на нет. Ждать придется долго, скорее никогда. Добавлено - Маста вот как будет async.parallel function parallel(tasks, callback) { var running = 0, key = 0, iterator = tasks.values(), results = []; while (true) { var item = iterator.next(); if (item.done) { if (running <= 0) callback(null, results); return; } running++; item.value((err, result) => { if (err) { running = Infinity; return callback(err); } running--; results[key++] = result; if (running <= 0) callback(null, results); }); } } - Да еще одно замечание мне пришлось включить модуль babel-polifill т.к в массивы Node 10 не имеют values(). Добавлено Цитата Cfon @ - Да еще одно замечание мне пришлось включить модуль babel-polifill т.к в массивы Node 10 не имеют values(). Необязательно вспомни цикл for of. Что там юзается? Да-да неудивляйся тоже итератор! tasks.values() можно заменить на tasks[Symbol.iterator]() - Вау Маста! Работает! |
Сообщ.
#11
,
|
|
|
А вот и async.waterfall
function waterfall(tasks, callback) { var iterator = tasks.values(); var item = iterator.next(); function next(args) { args.push((err, ...args) => { item = iterator.next(); if (err || item.done) return callback(err, ...args); next(args); }); item.value(...args); } next([]); }; //test waterfall waterfall([ cb => {console.log('1'); setTimeout(() => cb(null, 'one', 'two'), 1000)}, (arg1, arg2, cb) => {console.log('2'); setTimeout(() => cb(null, `${arg1} ${arg2} three`), 1000)}, (arg, cb) => {console.log('3'); setTimeout(() => cb(null, `${arg} done`), 1000)} ], (err, result) => { if (err) return console.log(err); console.log(result); }); console.log('test waterfall'); // 1 // test waterfall // 2 // 3 // one two three done с waterfall пришлось немного повозится, поскольку в ней результаты выполнения предыдущей функции должны передаваться следущей. Как видите я заюзал ...args и в конце каждой функции добавлял колбэк согласно требованию. |
Сообщ.
#12
,
|
|
|
Чем отличается async.series от async.waterfall?
Series позволяет выполнять задачи последовательно, передавая результат своей работы в массив results конечного колбэка. При этом каждый результат будет сохраняться в соответствующей ячейке. Waterfall также выполняет задачи последовательно, но с тем отличием, что результаты предыдущей задачи могут передаваться следующей. Последняя задача передаёт свой результат в конечный колбэк. Сами задачи в обоих случаях могут выполняться как синхронно так и асинхронно. Понятно, что в случае только синхронных задач юзать series, waterfall, как впрочем parallel не имеет смысла по очевидной причине |