Почему вам нужно ждать AJAX звонков в JS, а не C#? - PullRequest
0 голосов
/ 01 августа 2020

В Javascript Я привык делать вызовы API, используя любую библиотеку, используя ключевое слово await. Это эффективно реализует обещание и предотвращает выполнение следующей строки кода до тех пор, пока эта строка кода не будет завершена.

const response = await fetch("http://some-url.com/endpoint", { /* options */ });
const result = response.json();

Это не кажется необходимым в C#. Я могу сделать вызов, блокирующий потоки, и он не перейдет к следующей строке без использования await.

var response = someApi.get("http://some-url.com/endpoint");
var str = "This line will wait for get() to complete";

Еще больше усложняет ситуацию, я вижу, что многие библиотеки C# имеют два метода для вызова API - get () и getAsyn c ().

Реализует ли C# функциональность, которую ключевое слово await в JS дает нам изначально? В чем тогда смысл этих async методов в C#? Я понимаю, что JS является однопоточным, но не каждое консольное приложение C# также однопоточное, пока вы не начнете создавать в нем свои собственные потоки?

1 Ответ

2 голосов
/ 01 августа 2020

Во-первых, не совсем честно сравнивать C# с JavaScript - это разные языки с разным временем выполнения и разными асинхронными механизмами.

JavaScript не является многопоточным - он работает на одна нить; следовательно, фактически ничего не может делать асинхронно. Чтобы преодолеть это, среда выполнения JS использует событие l oop, которое позволяет вам различать код, который должен блокировать основной поток, и код, который не должен блокироваться (например, и AJAX вызов - после запроса http отправлено, JS ничего не может сделать, кроме как подождать, поэтому вместо этого он будет выброшен на событие l oop до тех пор, пока не будет возвращен HTTP-ответ, затем он получит событие l oop и начнет выполнение и код, который зависит от ответа). Ключевые слова asyn c и await фактически являются синтаксисом c сахаром для обертывания функциональности Promise: следующий код -

function async makeCall()
{
  const response = await makeHttpCall(httpRequest);
  console.log(response);
}

похож на (но не совсем то же самое, что и ) -

function makeCall()
{
  makeHttpCall(httpRequest)
      .then(response => console.log(response));
}

Обещайте, что это пример некоторого кода, который будет помещен в событие l oop - JavaScript, будет планировать выполнение этого кода, чтобы он мог запускаться асинхронно на одном thread.

В C# у нас фактически есть много потоков, с которыми нужно работать, поэтому мы можем выполнять операцию asyn c одновременно. Чтобы упростить эту задачу, C# предоставляет нам параллельную библиотеку задач (TPL) , которая предоставляет ряд API-интерфейсов, которые значительно упрощают работу с многопоточным и запланированным выполнением кода. https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl

Точно так же, как JavaScript - TPL и C# дают нам одинаковый синтаксис c сахара для использования 'asyn c' и 'await', и поскольку C# является языком более низкого уровня, большее количество библиотек предоставляют разработчику две реализации для кода, который не должен блокировать текущий или вызывающий поток.

это заблокирует все выполнение до завершения операции (текущий и вызывающий поток)

HttpResponse response = MakeHttpCall();

это заблокирует текущий поток выполнения, но вернет выполнение в вызывающий поток

 HttpResponse response = await MakeHttpCallAsync();

это запустит asyn c, но вернет задачу для отслеживания выполнения

 Task responseTask = MakeHttpCallAsync();
 // execute code here while we wait for the http response 
 
 HttpResponse response = await responseTask; // or responseTask.Result but not ideal 

TPL (любой код C#, использующий тип Task ) решит, должен ли новый поток может быть создан или если код должен быть запланирован в текущем потоке с использованием контекста синхронизации.

Также может быть полезно подумать о типе Task в C# аналогично тип Обещание в JS (очевидно, не то же самое, но есть сходства)

...