Короткая зарисовка на тему управления потоком выполнения с помощью async. В большом приложении профит от применения этого модуля трудно переоценить. Я использую его уже не первый год и сегодня попробую показать пару приемов. На мой взгляд async - лучшее на текущий момент лекарство от Callback Hell.
Например мы получаем данные...
... после чего с ними необходимо произвести определенные манипуляции...
Код нашего приложения может выглядеть следующим образом:
Результат работы приложения:
Но если мы решим вывести в консоль результат только после завершения обработки всех данных, да еще и обработать ошибки, которые могут возникнуть в процессе наших асинхронных манипуляций, то модуль async будет очень даже кстати:
Усложняем задачу - после получения данных выполняем две асинхронные манипуляции с каждым полученным объектом параллельно:
Для полноты ощущений добавим еще одну манипуляцию, которая будет выполняться только после завершения первых двух:
Но какого коллайдера мы дважды проверяем наличие ошибок если есть возможность получить их в одном месте?
Для правды жизни выкинем ошибку в самой первой функции:
Вот теперь все по фэн-шую. Если вы все еще кипятите, то сейчас самое время начать избавляться от бесконечной лапши коллбэков.
На этом прощаюсь, и да пребудет с вами сила :)
Например мы получаем данные...
function getData(cb) { setTimeout(function() { console.log('Getting data...'); return cb([{a: 3}, {a: 5}]); }, 1000); }
... после чего с ними необходимо произвести определенные манипуляции...
function add(obj, cb) { setTimeout(function() { obj.b = obj.a + obj.a; console.log('%d plus %d = %d', obj.a, obj.a, obj.b); cb(); }, 1000); }
Код нашего приложения может выглядеть следующим образом:
getData(function(data) { data.forEach(function(obj) { add(obj, function() { console.log('obj:', obj); }); }); }); function getData(cb) { setTimeout(function() { console.log('Getting data...'); return cb([{a: 3}, {a: 5}]); }, 1000); } function add(obj, cb) { setTimeout(function() { obj.b = obj.a + obj.a; console.log('%d plus %d = %d', obj.a, obj.a, obj.b); cb(); }, 1000); }
Результат работы приложения:
Но если мы решим вывести в консоль результат только после завершения обработки всех данных, да еще и обработать ошибки, которые могут возникнуть в процессе наших асинхронных манипуляций, то модуль async будет очень даже кстати:
var async = require('async'); getData(function(data) { async.each(data, function(obj, next) { add(obj, next); }, function(err) { if (err) console.log('err:', err); console.log('data:', data); }); }); function getData(cb) { setTimeout(function() { console.log('Getting data...'); return cb([{a: 3}, {a: 5}]); }, 1000); } function add(obj, cb) { setTimeout(function() { obj.b = obj.a + obj.a; console.log('%d plus %d = %d', obj.a, obj.a, obj.b); cb(); }, 1000); }
Усложняем задачу - после получения данных выполняем две асинхронные манипуляции с каждым полученным объектом параллельно:
var async = require('async'); getData(function(data) { async.each(data, function(obj, next) { async.parallel([ function(cb){ add(obj, cb); }, function(cb){ multiply(obj, cb); } ], next); }, function(err) { if (err) console.log('err:', err); console.log('data:', data); }); }); function getData(cb) { setTimeout(function() { console.log('Getting data...'); return cb([{a: 3}, {a: 5}]); }, 1000); } function add(obj, cb) { setTimeout(function() { obj.b = obj.a + obj.a; console.log('%d plus %d = %d', obj.a, obj.a, obj.b); cb(); }, 1000); } function multiply(obj, cb) { setTimeout(function() { obj.c = obj.a * obj.a; console.log('%d times %d = %d', obj.a, obj.a, obj.c); cb(); }, 1000); }
Для полноты ощущений добавим еще одну манипуляцию, которая будет выполняться только после завершения первых двух:
var async = require('async'); getData(function(data) { async.each(data, function(obj, next) { async.parallel([ function(cb){ add(obj, cb); }, function(cb){ multiply(obj, cb); } ], next); }, function(err) { if (err) console.log('err:', err); async.each(data, function(obj, next) { subtract(obj, next); }, function(err) { if (err) console.log('err:', err); console.log('data:', data); }); }); }); function getData(cb) { setTimeout(function() { console.log('Getting data...'); return cb([{a: 3}, {a: 5}]); }, 1000); } function add(obj, cb) { setTimeout(function() { obj.b = obj.a + obj.a; console.log('%d plus %d = %d', obj.a, obj.a, obj.b); cb(); }, 1000); } function multiply(obj, cb) { setTimeout(function() { obj.c = obj.a * obj.a; console.log('%d times %d = %d', obj.a, obj.a, obj.c); cb(); }, 1000); } function subtract(obj, cb) { setTimeout(function() { obj.d = obj.c - obj.b; console.log('%d minus %d = %d', obj.c, obj.b, obj.d); cb(); }, 1000); }
Но какого коллайдера мы дважды проверяем наличие ошибок если есть возможность получить их в одном месте?
Для правды жизни выкинем ошибку в самой первой функции:
var async = require('async'); getData(function(data) { async.waterfall([ function(callback){ async.each(data, function(obj, next) { async.parallel([ function(cb){ add(obj, cb); }, function(cb){ multiply(obj, cb); } ], next); }, callback); }, function(callback){ async.each(data, function(obj, next) { subtract(obj, next); }, callback); } ], function(err) { if (err) console.log('err:', err.message); console.log('data:', data); }); }); function getData(cb) { setTimeout(function() { console.log('Getting data...'); return cb([{a: 3}, {a: 5}]); }, 1000); } function add(obj, cb) { setTimeout(function() { if (obj.a === 3) return cb(new Error('Achtung!')); obj.b = obj.a + obj.a; console.log('%d plus %d = %d', obj.a, obj.a, obj.b); cb(); }, 1000); } function multiply(obj, cb) { setTimeout(function() { obj.c = obj.a * obj.a; console.log('%d times %d = %d', obj.a, obj.a, obj.c); cb(); }, 1000); } function subtract(obj, cb) { setTimeout(function() { obj.d = obj.c - obj.b; console.log('%d minus %d = %d', obj.c, obj.b, obj.d); cb(); }, 1000); }
Вот теперь все по фэн-шую. Если вы все еще кипятите, то сейчас самое время начать избавляться от бесконечной лапши коллбэков.
На этом прощаюсь, и да пребудет с вами сила :)
Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации