Skip to content

Instantly share code, notes, and snippets.

@ashl1
Last active December 10, 2017 15:26
Show Gist options
  • Save ashl1/9b1150e23a9fef2e36a81c8d944995d8 to your computer and use it in GitHub Desktop.
Save ashl1/9b1150e23a9fef2e36a81c8d944995d8 to your computer and use it in GitHub Desktop.
Promise chain graph
(({timeout1, timeout2}) => {
const startOp = (name, timeout) => () => {
console.log(name + ' started at ' + Date.now())
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, timeout);
});
}
const start = Date.now();
const op1 = startOp('StartOp1', timeout1)();
const op2 = startOp('StartOp2', timeout2)();
op1.then(function() {
// Fires when op1 is successful; doesn't care about op2
console.log("op1 done after " + (Date.now() - start) + "ms");
});
op2.then(function() {
// Fires when op2 is successful; doesn't care about op1
console.log("op2 done after " + (Date.now() - start) + "ms");
});
Promise.all([op1, op2]).then(function() {
// Fires when BOTH ops are successful
console.log("both done after " + (Date.now() - start) + "ms");
});
})({
timeout1: 1000,
timeout2: 2000
})
// We can has as many points to branch as want. Thus we can make a graph of executions
(({timeout1, timeout2}) => {
const startOp = (name, timeout) => async () => {
console.log(name + ' started at ' + Date.now())
return new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, timeout);
});
}
const start = Date.now();
const op1 = startOp('StartOp1', timeout1)();
const op2 = op1.then(() => startOp('StartOp2', timeout2)());
Promise.all([op1, op2]).then(function() {
// Fires when BOTH ops are successful
console.log(Date.now() + " both done after " + (Date.now() - start) + "ms");
});
op1.then(function() {
// Fires when op1 is successful; doesn't care about op2
console.log(Date.now() + " op1 done after " + (Date.now() - start) + "ms");
});
op2.then(function() {
// Fires when op2 is successful; doesn't care about op1
console.log(Date.now() + " op2 done after " + (Date.now() - start) + "ms");
});
})({
timeout1: 1000,
timeout2: 2000
})
@pkuderov
Copy link

pkuderov commented Oct 11, 2017

не обращай внимания на обертку в класс (это шарповая необходимость) и то, что все методы статические.

namespace Numbers
{
    internal class Program
    {
        public static async Task Main()
        {
            await TestAsync();
        }

        private static async Task TestAsync()
        {
            const string task1Name = "task1";
            const string task2Name = "task2";

            Console.WriteLine($"test is started at {DateTime.Now.TimeOfDay}");
            Console.WriteLine("============================================");

            // создаем и запускаем задачи (разными способами - явным созданием задачи 
            // и через вызов метода, который создает и возвращает задачу)
            var task1 = RunAsync(task1Name, TimeSpan.FromSeconds(3));
            var task2 = Task.Run(async () =>
            {
                Console.WriteLine($"{task2Name} is started at {DateTime.Now.TimeOfDay}");
                await Task.Delay(TimeSpan.FromSeconds(5));
            });

            var name = new Dictionary<Task, string>
            {
                {task1, task1Name},
                {task2, task2Name}
            };

            // создаем обработчики завершения каждой из задач
            var task1Handler = HandleTaskAsync(task1Name, task1);

            // а это старый путь с помощью ContinueWith (у вас это .then)
            var task2Handler = task2.ContinueWith(
                task => Console.WriteLine($"{name[task]} is finished at {DateTime.Now.TimeOfDay}")
            );

            // а так можно локально лямбду сделать
            Func<Task> handleBoth = async () =>
            {
                await Task.WhenAll(task1, task2);
                Console.WriteLine($"both are finished at {DateTime.Now.TimeOfDay}");
            };

            // а это уже синтаксис локальной функции (ввели недавно)
            async Task HandleFirstFinished()
            {
                var finished = await Task.WhenAny(task1, task2);
                Console.WriteLine($"{name[finished]} is finished first at {DateTime.Now.TimeOfDay}");
            }

            // создаем обработчики "завершены оба" и "завершен первый из"
            var bothTasksHandler = handleBoth();
            var anyTaskHandler = HandleFirstFinished();

            // ждем асинхронно завершения всех обработчиков.Если не ожидать, то программа завершится, не дожидаясь окончания :)
            await Task.WhenAll(task1Handler, task2Handler, bothTasksHandler, anyTaskHandler);

            Console.WriteLine("============================================");
            Console.WriteLine($"test is finished at {DateTime.Now.TimeOfDay}");
        }

        private static async Task HandleTaskAsync(string name, Task task)
        {
            await task;
            Console.WriteLine($"{name} is finished at {DateTime.Now.TimeOfDay}");
        }

        private static async Task RunAsync(string name, TimeSpan timeout)
        {
            Console.WriteLine($"{name} is started at {DateTime.Now.TimeOfDay}");
            await Task.Delay(timeout);
        }
    }
}

Output is:

test is started at 18:04:46.1795137
============================================
task1 is started at 18:04:46.1877900
task2 is started at 18:04:46.1956725
task1 is finished at 18:04:49.1918602
task1 is finished first at 18:04:49.1922778
both are finished at 18:04:51.2103053
task2 is finished at 18:04:51.2107312
============================================
test is finished at 18:04:51.2112608

@pkuderov
Copy link

pkuderov commented Oct 11, 2017

namespace Numbers
{
    internal class Program
    {
        public static async Task Main()
        {
            await TestAsync();

            Task.Wait(StartTest());
        }

        private static async Task TestAsync()
        {
            const string task1Name = "task1";
            const string task2Name = "task2";

            Console.WriteLine($"test is started at {DateTime.Now.TimeOfDay}");
            Console.WriteLine("============================================");

            // создаем и запускаем задачи (разными способами - явным созданием задачи и через вызов метода)
            var task1 = RunAsync(task1Name, TimeSpan.FromSeconds(3));
            var task2 = RunAsync(task1Name, TimeSpan.FromSeconds(5));

            // создаем обработчики завершения каждой из задач
            var task1Handler = HandleTaskAsync(task1Name, task1);
            var task2Handler = HandleTaskAsync(task2Name, task2);
            var bothTasksHandler = HandleBothTasksAsync(task1, task2);

            // ждем асинхронно завершения всех обработчиков.Если не ожидать, то программа завершится, не дожидаясь окончания :)
            await Task.WhenAll(task1Handler, task2Handler, bothTasksHandler);

            Console.WriteLine("============================================");
            Console.WriteLine($"test is finished at {DateTime.Now.TimeOfDay}");
        }

        private static async Task HandleTaskAsync(string name, Task task)
        {
            await task;
            Console.WriteLine($"{name} is finished at {DateTime.Now.TimeOfDay}");
        }
        private static async Task HandleBothTasksAsync(params Task[] tasks)
        {
            await Task.WhenAll(tasks);
            Console.WriteLine($"both are finished at {DateTime.Now.TimeOfDay}");
        }

        private static async Task RunAsync(string name, TimeSpan timeout)
        {
            Console.WriteLine($"{name} is started at {DateTime.Now.TimeOfDay}");
            await Task.Delay(timeout);
        }


        private static Task StartTest()
        {
            const string task1Name = "task1";
            const string task2Name = "task2";

            Console.WriteLine($"test is started at {DateTime.Now.TimeOfDay}");
            Console.WriteLine("============================================");

            // создаем и запускаем задачи
            var task1 = StartTask(task1Name, TimeSpan.FromSeconds(3));
            var task2 = StartTask(task2Name, TimeSpan.FromSeconds(5));

            // создаем обработчики завершения каждой из задач
            var task1Handler = task1.ContinueWith(
                task => Console.WriteLine($"{task1Name} is finished at {DateTime.Now.TimeOfDay}")
            );
            var task2Handler = task2.ContinueWith(
                task => Console.WriteLine($"{task2Name} is finished at {DateTime.Now.TimeOfDay}")
            );
            var bothTasksHandler = Task
                .WhenAll(task1, task2)
                .ContinueWith(
                    _ => Console.WriteLine($"both are finished at {DateTime.Now.TimeOfDay}")
                );

            // возвращаем задачу, обрабатывающую завершение теста
            return Task
                .WhenAll(task1Handler, task2Handler, bothTasksHandler)
                .ContinueWith(_ =>
                {
                    Console.WriteLine("============================================");
                    Console.WriteLine($"test is finished at {DateTime.Now.TimeOfDay}");
                });
        }

        private static Task StartTask(string name, TimeSpan timeout)
        {
            Console.WriteLine($"{name} is started at {DateTime.Now.TimeOfDay}");
            return Task.Delay(timeout);
        }
}

И вывод:

test is started at 18:11:33.1876868
============================================
task1 is started at 18:11:33.1952876
task2 is started at 18:11:33.2029642
task1 is finished at 18:11:36.2000966
task1 is finished first at 18:11:36.2006441
both are finished at 18:11:38.2132435
task2 is finished at 18:11:38.2136049
============================================
test is finished at 18:11:38.2140603
test is started at 18:11:38.2151002
============================================
task1 is started at 18:11:38.2157185
task2 is started at 18:11:38.2161499
task1 is finished at 18:11:41.2164911
task2 is finished at 18:11:43.2163368
both are finished at 18:11:43.2163510
============================================
test is finished at 18:11:43.2174240

@pkuderov
Copy link

pkuderov commented Oct 11, 2017

Если у тебя есть цепочка асинхронных операций - намного удобнее использовать async/await:

var res1 = await operation1(input);
if (res1 == "good")
{
    var res2 = await operation2(res1);
    await Task.WhenAll(operation3_1(res2), operation3_2 (res2));
}
await operation4(res1);

С continuation-цепочками это выглядело бы так:

operation1(input)
    .ContinueWith(
        task =>
        {
            if (task.Result == "good")
            {
                return operation2(task.Result)
                    .ContinueWith(task2 => Task.WhenAll(operation3_1(task2.Result), operation3_2(task2.Result)))
                    .ContinueWith(_ => task);
            }
            return task
        })
    .ContinueWith(task => operation4(task.Result));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment