Задача на Event Loop
Добрый день! Столкнулся с интересной задачей и не знаю как решить.
function one(callback) { setTimeout( function() { callback("First"); }, Math.random() * 100); } function two(callback) { setTimeout( function() { callback("Second"); }, Math.random() * 100); } function three(callback) { setTimeout( function() { callback("Third"); }, Math.random() * 100); } function runCallback(s) { console.log(s); } Нужно вызвать функции one, two и three в правильной последовательности, чтобы в консоль вывелось A, B и C в нужном порядке. При этом использовать можно все, даже дописывать runCallback, но сами функции менять нельзя. :help: |
Эту задачу можно понимать по разному.
В простейшем варианте вы вызываете следующую функцию из runCallback когда закончилась предыдущая. Но можно и такое изобразить: function stream(log, ...args) { let index = 0; const results = new Map(); const callback = (i, result) => { if(i === index) { while(true) { log(result); if(!results.has(++index)) break; result = results.get(index); results.delete(index); } } else { results.set(i, result); } }; args.forEach((func, i) => func(result => callback(i, result))); } stream(runCallback, one, two, three)получив максимальную возможную скорость вызовов. |
Понял, спасибо! :)
|
Предложу решение "в лоб"...
<!DOCTYPE html> <html> <head> <!-- <script src='https://code.jquery.com/jquery-latest.min.js'></script> --> <style type='text/css'> </style> <script> function one(callback) { setTimeout( function() { callback("First"); }, Math.random() * 2000); } function two(callback) { setTimeout( function() { callback("Second"); }, Math.random() * 2000); } function three(callback) { setTimeout( function() { callback("Third"); }, Math.random() * 2000); } function runCallback(s) { const o = document.createElement('p') o.textContent = s document.querySelector('body').appendChild(o) } // Вот собственно решение... const test1 = res => { runCallback(res) three(runCallback) } const test2 = res => { runCallback(res) two(test1) } one(test2) </script> </head> <body> </body> </html> |
Или вовсе так...
<!DOCTYPE html> <html> <head> <!-- <script src='https://code.jquery.com/jquery-latest.min.js'></script> --> <style type='text/css'> </style> <script> function one(callback) { setTimeout( function() { callback("First"); }, Math.random() * 2000); } function two(callback) { setTimeout( function() { callback("Second"); }, Math.random() * 2000); } function three(callback) { setTimeout( function() { callback("Third"); }, Math.random() * 2000); } function runCallback(s) { const o = document.createElement('p') o.textContent = s document.querySelector('body').appendChild(o) } // Вот собственно решение... one(res => { runCallback(res) two(res => { runCallback(res) three(runCallback) }) }) </script> </head> <body> </body> </html> |
Я считаю предыдущие решения некорректными, т.к. при вызове функций используется другой callback. Не сам runCallback
Предлагаю свое решение function one(callback) { setTimeout( function() { callback("First"); }, Math.random() * 1000); } function two(callback) { setTimeout( function() { callback("Second"); }, Math.random() * 1000); } function three(callback) { setTimeout( function() { callback("Third"); }, Math.random() * 1000); } function runCallback(s) { console.log(s); } let console; function call (...funs) { const cl = window.console.log let i = 0 console = { log (...args) { cl(...args) if (i<funs.length) funs[i++](runCallback) else console = window.console; } } funs[i++](runCallback) } call(one, two, three) |
Цитата:
имхо, раз уж runCallback и callback у функций не склеены изначально, то между ними и надо втыкать "мидлвар". А в целом задача решается в одну строку, если не городить велосипеды: // ----- условие -------------- function one(callback) { setTimeout( function() { callback("First"); }, Math.random() * 100); } function two(callback) { setTimeout( function() { callback("Second"); }, Math.random() * 100); } function three(callback) { setTimeout( function() { callback("Third"); }, Math.random() * 100); } function runCallback(s) { console.log(s); } // ----- решение -------------- Promise.all([one, two, three].map(f => new Promise(f))).then(r => r.forEach(runCallback)); |
Alexandroppolus, но вся суть в велосипедах.)
Твоя версия запускает все функции сразу и разом выводит всё когда получены все результаты. Время первого вывода на экран = Время выполнения самой медленной функции. Время последнего вывода на экран = Время выполнения самой медленной функции. Версии voraa и ksa запускают функции и выводят результат по порядку. Время первого вывода на экран = Время выполнения первой функции. Время последнего вывода на экран = Сумма времени выполнения всех функций. Мой велосипед запускает все функции сразу, но выводит по мере исполнения и по порядку.) Время первого вывода на экран = Время выполнения первой функции. Время последнего вывода на экран = Время выполнения самой медленной функции. В худшем случае: если первая функция - самая медленная, то результат будет как у тебя, но это крайний вариант. Примерно так работают async стримы, только там есть ещё ограничение на количество одновременно запущенных потоков, чтоб все ресурсы не съело.) |
Aetae, вариант со стримом прикольный, жизненный. Возможно, так и было в исходном условии, но Himmelin сыграл в испорченный телефон.
|
Aetae,
ksa, voraa, Alexandroppolus, :thanks: |
Часовой пояс GMT +3, время: 11:23. |