为什么需要在JS中等待而不是在C#中等待AJAX​​调用?

时间:2020-08-01 14:58:00

标签: javascript c# asynchronous async-await

在Javascript中,我习惯使用await关键字通过任何库进行API调用。这样可以有效地实现承诺,并防止在下一行代码完成之前执行下一行代码。

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()和getAsync()。

C#是否实现JS中的await关键字本机提供给我们的功能?那么在C#中这些async方法的意义是什么?我了解JS是单线程的,但是在您开始在其中创建自己的线程之前,不是每个C#控制台应用程序也都是单线程的吗?

1 个答案:

答案 0 :(得分:2)

首先,将C#与JavaScript进行比较并不完全公平-它们是具有不同运行时和不同异步机制的不同语言。

JavaScript不是多线程的-它在一个线程上运行;因此实际上不能异步执行任何操作。为了克服这个问题,JS运行时使用了事件循环,它使您可以区分需要阻塞主线程的代码和不应该阻塞的代码(例如和AJAX调用-发送HTTP请求后,JS无法执行的操作)但请稍候,因此它会被引发事件循环,直到返回http响应,然后将其拉出事件循环并开始执行和取决于响应的代码。 'async'和'await'关键字是有效的语法糖,用于包装Promise的功能: 以下代码-

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

与(但不完全相同)-

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

一个无用的例子,它将放在事件循环中-JavaScript将调度该代码的执行,以便它看起来可以在单个线程上异步运行。

在C#中,我们实际上有许多线程可以使用,因此我们可以同时执行异步操作。为了简化操作,C#为我们提供了任务并行库(TPL),该库将提供一系列API,使处理多线程和计划的代码执行更加简单。
https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl

以与JavaScript相同的方式-TPL和C#为我们提供了使用'async'和'await'关键字的相同语法糖,并且由于C#是较低级的语言,因此更多的库为开发人员提供了两种实现用于不需要阻塞当前线程或调用线程的代码。

这将阻止所有执行,直到操作完成为止(当前和 调用线程)

HttpResponse response = MakeHttpCall();

这将阻止当前执行线程,但将执行返回给 调用线程

 HttpResponse response = await MakeHttpCallAsync();

这将启动异步操作,但将返回一个Task以跟踪 执行

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

TPL(使用 Task 类型的任何C#代码)将决定是否应该创建新线程,或者是否应该使用同步上下文在当前线程上调度代码。

将C#中的 Task 类型与JS中的 Promise 类型相提并论(显然不尽相同,但有相似之处)< / p>