Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Задача на Event Loop (https://javascript.ru/forum/misc/83137-zadacha-na-event-loop.html)

Himmelin 27.09.2021 14:45

Задача на 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:

Aetae 27.09.2021 15:35

Эту задачу можно понимать по разному.
В простейшем варианте вы вызываете следующую функцию из 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)
получив максимальную возможную скорость вызовов.

Himmelin 27.09.2021 15:44

Понял, спасибо! :)

ksa 27.09.2021 20:43

Предложу решение "в лоб"...

<!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>

ksa 27.09.2021 20:48

Или вовсе так...
<!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>

voraa 27.09.2021 21:34

Я считаю предыдущие решения некорректными, т.к. при вызове функций используется другой 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)

Alexandroppolus 27.09.2021 22:21

Цитата:

Сообщение от voraa
Я считаю предыдущие решения некорректными, т.к. при вызове функций используется другой callback. Не сам runCallback

то есть вместо патча runCallback сделать патч console.log - это будет честнее? :D

имхо, раз уж 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));

Aetae 28.09.2021 02:07

Alexandroppolus, но вся суть в велосипедах.)
Твоя версия запускает все функции сразу и разом выводит всё когда получены все результаты.
Время первого вывода на экран = Время выполнения самой медленной функции.
Время последнего вывода на экран = Время выполнения самой медленной функции.

Версии voraa и ksa запускают функции и выводят результат по порядку.
Время первого вывода на экран = Время выполнения первой функции.
Время последнего вывода на экран = Сумма времени выполнения всех функций.

Мой велосипед запускает все функции сразу, но выводит по мере исполнения и по порядку.)
Время первого вывода на экран = Время выполнения первой функции.
Время последнего вывода на экран = Время выполнения самой медленной функции.

В худшем случае: если первая функция - самая медленная, то результат будет как у тебя, но это крайний вариант. Примерно так работают async стримы, только там есть ещё ограничение на количество одновременно запущенных потоков, чтоб все ресурсы не съело.)

Alexandroppolus 28.09.2021 09:09

Aetae, вариант со стримом прикольный, жизненный. Возможно, так и было в исходном условии, но Himmelin сыграл в испорченный телефон.

рони 28.09.2021 09:40

Aetae,
ksa,
voraa,
Alexandroppolus,
:thanks:


Часовой пояс GMT +3, время: 15:46.