【问题标题】:Why is a function async when it calls another async function?为什么一个函数在调用另一个异步函数时是异步的?
【发布时间】:2021-08-07 06:16:32
【问题描述】:

我以为我理解了如何使用 async 和 await 直到我看到下面的代码 sn-p。

因此,电影输入文本框附加了一个 onInput 事件处理函数。其中称为 fetchData 异步函数,该函数使用 await 关键字等待 axios.get 函数的结果。

我的问题是,为什么我们需要让 onInput 函数也异步?我的意思是,fetchData 函数是异步的。这意味着,它将等到 axios.get 被解决,并且执行将暂停,直到 axios.get 被解决。所以当行 const movies = fetchData(event.target.value);执行时,将执行 fetchData 函数,该函数将在 await axios.get 语句处暂停。那么为什么我们需要在调用 fetchData 时使用 await 并使 onInput 异步呢??

const fetchData = async(searchTerm)=>{
    const results =  await axios.get('http://www.omdbapi.com/', {
    params:{
        apikey:'d9835cc5',
        s: searchTerm
        }

    });
    return results.data.Search;
}

    const movieInput = document.querySelector('input');
    
    
    const onInput = async event => {
        const movies = await fetchData(event.target.value);
        console.log(movies);
    }
    
    movieInput.addEventListener('input', onInput);

【问题讨论】:

    标签: javascript async-await


    【解决方案1】:

    我的意思是,fetchData 函数是异步的。这意味着,它会等到 axios.get 被解决,然后执行将暂停,直到 axios.get 被解决。

    这个概念隐藏了很多可能令人困惑的细节,例如使用回调函数恢复暂停的执行。

    • async 函数不会暂停其调用者的执行。

      相反,它们返回一个承诺,该承诺将使用从执行async 函数体返回的语法值来解决。需要明确的是,显然从 async 函数体内返回的值直接返回给调用者 - 调用者得到了一个承诺。

    • await operator 执行时会设置回调,以便在其操作数承诺完成时设置回调。实际上,它调用其 promise 操作数的 then 方法来提供一组 onfulfilledonrejected 回调,然后将当前执行上下文存储在内存中并返回到事件循环。

      当它收到来自承诺结算的回调时,await 操作符会恢复它之前保存的执行上下文。如果等待的承诺被拒绝,await 抛出拒绝原因。如果已完成,await 将继续执行并返回 Promise 的已完成值作为执行 await 运算符的结果。

    从历史上看,await 从来都不是保留关键字 - 在 ES3 中未提及,在 ES6 (ECMAScript 2015) 中未提及,但在截至 2021 年 5 月的当前 ECMAscript 草案中是保留字。

    因此,为了保持与网络上代码的兼容性,await 仅在出现在 async 函数内时才被识别为运算符 - 使其在 async 函数体之外作为标识符可用。

    同样,async 关键字在历史上并未保留,但通过要求在以前版本的 JavaScript 中会产生意外标识符错误的位置使用它,能够在没有可比性问题的情况下引入。 function 关键字之前或箭头函数表达式之前的含义。

    最后,您需要将onInput 声明为async 函数,因为await 在其主体中用作运算符。如果没有 async 声明,await 将被视为标识符而不是运算符的名称。

    附带说明,onInput 返回的承诺将被丢弃,并且可能会以当前形式生成未捕获的承诺拒绝错误。


    要回答“为什么await 需要在onInput 函数中使用?”这个略有不同的问题,fetchData 返回的值是一个待处理的承诺。为了将movies 设置为results.data.SearchfetchData 中获得的值,您需要等待返回的promise 的执行值。使用async/await 是这样做的一种方法。另一种是通过调用then 方法为从fetchData 返回的promise 添加一个履行处理程序。

    【讨论】:

    • 我认为 async 令牌从未被认为是一种兼容性解决方案。即使没有必要,it's still a good idea.
    • @Bergi 我已经使部分答案更加直接。检查 Firefox 显示 asyncawait 至今仍可用作 async 函数之外的标识符。当然同意在异步函数声明之前使用async 是个好主意,更不用说它会创建一个AsyncFuntion 对象而不是Function 对象!
    • @traktor 是否会在“const movies = await fetchData(event.target.value);”行暂停 oninput 函数的执行?我理解它应该暂停并等待承诺解决。对吗?
    • @theju112t JavaScript 是单线程的 - 当从事件循环任务管理器调用时,脚本代码会继续运行,直到它返回到任务管理器。 onInput 中的 await 操作符存储当前执行环境并返回事件循环,使其他事件驱动的 JavaScript 能够从事件循环中被调用和运行。当添加到fetchData()...) 承诺的处理程序之一被调用时,onInput 中的await 运算符表达式的评估将恢复。如果您愿意,可以将其称为“暂停”,但将其视为“暂停直到发生某些事情”可能更清楚。
    【解决方案2】:

    通常,您希望在程序的其余部分运行时执行 API 调用,因此 onInput 将是异步的。此外,javascript 要求 await 位于异步函数内部,因此代码也只是遵循其标准和规则。通常,一旦顶层是异步的,它里面的所有东西都只是遵循结构。更多信息可以在here找到。

    【讨论】:

      【解决方案3】:

      您在inInput 中使用await 运算符。这是一条 JavaScript 规则,使用 await 的函数必须是异步的,所以 inInput 也必须是异步的。看看这个答案:https://stackoverflow.com/a/56685416/13357440

      另外,MDN 有有用的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

      【讨论】:

      • 是的,我明白那部分.. await 只能在异步函数中使用。我的问题是,为什么我们需要让 onInput 完全异步? fetchData 是异步的并且它在特定的行上等待还不够吗?
      • @theju112t - 你不知道,它可以很容易地写成:const onInput = event => fetchOptions(event.target.value),最终结果将完全相同,返回一个承诺。有些人喜欢async 的注解,所以你可以一目了然函数返回一个promise,但这只是个人喜好。
      • @theju112t 如果您不需要调用fetchData 的结果,您可以使onInput 不是异步的并省略await,但您需要来自@987654333 的返回值@ 所以你需要使用awaitstackoverflow.com/questions/59953976/…
      • @atultw - but you want the return value from fetchData so you need to use await - 这是错误的。无论是否使用awaitonInput 都会返回完全相同的承诺。
      • @Adam ya 但我不希望承诺作为返回值。我想要承诺解决后的实际数据。
      猜你喜欢
      • 2020-08-26
      • 1970-01-01
      • 2020-09-18
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 2021-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多