0

有时我只是对使用 async/await 感到困惑。我试着学习了很多,但我总是质疑自己。所以这里有一个例子。我有一个导入的函数,它调用我的 react-app 上的后端以最终与 mongodb 对话。我的问题是,使用之间有什么区别:

async function handleChangeSelect(value,action){
  await getOneOrg(value.label).then(res=>{
        const updatedCategory = {...modal, [action.name]:value, categories:[{value:res.ans,label:res.ans}]}
        setModal(updatedCategory)
    }).catch(err=>console.log(err))
}

VS。

function handleChangeSelect(value,action){
   getOneOrg(value.label).then(res=>{
        const updatedCategory = {...modal, [action.name]:value, categories:[{value:res.ans,label:res.ans}]}
        setModal(updatedCategory)
    }).catch(err=>console.log(err))
}

他们似乎都在工作并且做同样的事情。比如我什么时候需要使用异步等待(我看到人们把它放在 .then 的父函数上。我知道 fetch/.then 已经是异步的,所以你不需要,但是你什么时候需要呢?)。把它放在父函数中有什么意义。我只是发现自己对何时使用此选项以及出于什么目的感到非常困惑。我需要例子,我很难掌握一个概念。另外,当你写这篇文章时,硬件/软件到底发生了什么?

4

3 回答 3

1

问题是在第一个示例中,您并没有真正使用 async/await。代码应该是:

async function handleChangeSelect(value,action){
  try {
    const res = await getOneOrg(value.label)
    const updatedCategory = {...modal, [action.name]:value, categories:[{value:res.ans,label:res.ans}]}
    setModal(updatedCategory)
  }
catch(err) { console.log(err)}
}

如果您有许多串联的 Promise,则使用 async-await 会产生更清晰、更易于理解的代码。

我不想详细介绍使用和幕后,因为网上有很多资源。

于 2020-11-18T21:05:02.553 回答
0

首先是异步/等待的“不正确”使用。从文档

异步函数是使用 async 关键字声明的函数。异步函数是 AsyncFunction 构造函数的实例,其中允许使用 await 关键字。async 和 await 关键字使异步、基于 Promise 的行为能够以更简洁的方式编写,避免了显式配置 Promise 链的需要

第一个例子应该是这样的:

async function handleChangeSelect(value, action) {

  const res = await getOneOrg(value.label).catch(err => console.log(err))

  const updatedCategory = {
    ...modal,
    [action.name]: value,
    categories: [{
      value: res.ans,
      label: res.ans
    }]
  }
  setModal(updatedCategory)
}

这会等待getOneOrg函数解析,然后再继续更新updatedCategory对象。

简短的回答 - 它消除了.then()到处链接的需要。

于 2020-11-18T21:04:34.840 回答
0

你的两个例子之间有一个关键的区别。这取决于他们将如何处理被调用await。我将用简化的术语来表示这两者。

第一个代码块:

const someAsyncOperation = ms => new Promise(res => setTimeout(res, ms, "hello"))

async function foo(){
  console.log("start async");
  await someAsyncOperation(1500)
    .then(res => console.log("do something with result:", res + "world"))
    .catch(() => console.error("no error will happen"));
  console.log("finish async");
}

async function main() {
  console.log("before foo()");
  await foo();
  console.log("after foo()");
}

main();

结果:

before foo()
start async
do something with result: helloworld
finish async
after foo()

与第二个代码块:

const someAsyncOperation = ms => new Promise(res => setTimeout(res, ms, "hello"))

async function foo(){
  console.log("start async");
  someAsyncOperation(1500)
    .then(res => console.log("do something with result:", res + "world"))
    .catch(() => console.error("no error will happen"));
  console.log("finish async");
}

async function main() {
  console.log("before foo()");
  await foo();
  console.log("after foo()");
}

main();

结果:

before foo()
start async
finish async
after foo()
do something with result: helloworld

如您所见,两种情况下的操作顺序不同

  1. 在第一种情况下,anawaitfoo()在继续之前完成整个过程。
  2. 第二,没有await,所以someAsyncOperation是火和忘记。您的代码将在执行之前完成,因此您永远不会收到成功或失败的通知。

另外,我必须注意,这在您使用await. 如果你不这样做,那么代码将永远不会等待它在任何一种情况下完成。

const someAsyncOperation = ms => new Promise(res => setTimeout(res, ms, "hello"))

async function foo(){
  console.log("start async");
  await someAsyncOperation(1500)
    .then(res => console.log("do something with result:", res + "world"))
    .catch(() => console.error("no error will happen"));
  console.log("finish async");
}

async function main() {
  console.log("before foo()");
  foo(); //no await
  console.log("after foo()");
}

main();

const someAsyncOperation = ms => new Promise(res => setTimeout(res, ms, "hello"))

async function foo(){
  console.log("start async");
  someAsyncOperation(1500)
    .then(res => console.log("do something with result:", res + "world"))
    .catch(() => console.error("no error will happen"));
  console.log("finish async");
}

async function main() {
  console.log("before foo()");
  foo(); //no await
  console.log("after foo()");
}

main();

这两个操作本质上是一样的。出现的地方有所不同,"finish async"但这只是因为我添加它是为了清楚地了解如何处理函数。在您的代码中,在 Promise 被触发后您没有其他任何内容,因此不会有任何区别。在这两种情况下foo(),它本身就是一场火灾,然后忘记,因为它没有被等待。因此,您是否等待内部操作都没有关系。

无论如何,没有一个通用的“更好”的方式来使用这些承诺。

有时您可能想要一个火灾并忘记功能,这样您就不必真正等待。举个简单的例子:

showSpinner();
getData()
    .then(data => {
        hideSpinner();
        showData(data);
    })
    .catch(error => {
        hideSpinner();
    }

/* do more stuff */

据推测,这是某种非关键数据——我们可以显示或不显示,但我们想移除微调器。

其他时候,您实际上可能希望在继续之前等待并验证操作是否成功。例如:

try {
    const user = await registerUser(userInfo);
    await processPayment(user);
} catch (error) {
    cancelTransaction();
    throw new RegistrationAndPaymentError(error);
}

/* do more stuff */

如果注册失败,我们必须抽空休息并避免继续该过程。

您选择哪一个取决于您希望如何处理给定的操作。有些你并不真正关心它们何时完成以及如何完成,其他人可能会阻止进一步的操作。

同样值得澄清的是,每个 async/await 使用都可以通过链接.then().catch(). 但是,有时链接很多 Promise 操作不如使用awaits 可读。大多数Promise API 操作也可以使用 async/await 来表达。因此,您选择哪一种通常取决于您喜欢哪一种。通常建议不要混合两种类型的语法 - 如果你这样做不会出错,但如果你坚持其中一种会更清楚。

综上所述,还建议使您的函数await能够进行异步操作。原因是,也许现在你可能不想等待他们完成,但将来你可能会。

使用您的第一段代码await handleChangeSelect()已经强制执行暂停,直到函数完成,所以它基本上没问题。诚然,如果它不混合会更好,await但它仍然没有错。.then().catch()

在不添加函数的情况下对函数完成做出反应的方法await(本质上,只使用promise API),您需要返回内部函数产生的promise。因此,您可以将其更改为:

function handleChangeSelect(value,action){
   return getOneOrg(value.label).then(res=>{
        const updatedCategory = {...modal, [action.name]:value, categories:[{value:res.ans,label:res.ans}]}
        setModal(updatedCategory)
    }).catch(err=>console.log(err))
}

这将使对函数完成做出反应成为可能:

const someAsyncOperation = ms => new Promise(res => setTimeout(res, ms, "hello"))

async function foo(){
  console.log("start async");
  return someAsyncOperation(1500)
    .then(res => console.log("do something with result:", res + "world"))
    .catch(() => console.error("no error will happen"))
    .then(() => console.log("finish async")); //we don't want any code after the async call
                                              //so, further code will be chained as .then()
}

async function main() {
  console.log("before foo()");
  await foo();
  console.log("after foo()");
}

main();

于 2020-11-18T22:31:18.507 回答