Last active
December 10, 2017 15:26
-
-
Save ashl1/9b1150e23a9fef2e36a81c8d944995d8 to your computer and use it in GitHub Desktop.
Promise chain graph
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(({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 | |
}) |
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
Если у тебя есть цепочка асинхронных операций - намного удобнее использовать 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
не обращай внимания на обертку в класс (это шарповая необходимость) и то, что все методы статические.
Output is: