【问题标题】:JavaScript Async/AwaitJavaScript 异步/等待
【发布时间】:2018-07-01 10:46:09
【问题描述】:

我正在尝试理解 JavaScript 异步/等待。我怎样才能重写下面的输出是“Hi”然后是“Bye”而不是“Bye”然后是“Hi”:

JSFiddle

sayHi() 
.then(sayBye);

async function sayHi() {
  await setTimeout(function() {
    $("#myOutput").text('hi');
  }, 1000);
}

async function sayBye() {
  $("#myOutput").text('bye');
}

【问题讨论】:

标签: javascript asynchronous


【解决方案1】:

您不能将 async/await 用于不返回 Promise 的函数

当调用异步函数时,它会返回一个 Promise。当 async 函数返回一个值时,Promise 将使用返回的值进行解析。当异步函数抛出异常或某个值时,Promise 将被抛出的值拒绝。

async 函数可以包含一个 await 表达式,它暂停 async 函数的执行并等待传递的 Promise 的解析,然后恢复 async 函数的执行并返回解析的值。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

通常它用于处理来自服务器的数据,因为当您有多个查询时,它可以覆盖前一个查询,您将处理错误的查询。

Async/await 可让您准确处理您正在等待的数据。

【讨论】:

    【解决方案2】:

    setTimeout 不返回Promise。创建一个辅助函数将其包装在 Promise 中,然后您可以 await 它。

    function delay(fn, t) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(fn());
            }, t);
        });
    }
    
    sayHi()
        .then(sayBye);
    
    async function sayHi() {
        await delay(() => {
            //$("#myOutput").text('hi');
            console.log("Hi");
        }, 1000);
    }
    
    async function sayBye() {
        //$("#myOutput").text('bye');
        console.log("Bye");
    }

    【讨论】:

    • 对于那些喜欢箭头功能的人...const delay = time => new Promise(res=>setTimeout(res,time));
    【解决方案3】:

    为了等待setTimeout,它需要被包装到 Promise 中。然后使用 async/await 你可以在没有 Promise then API 的情况下扁平化你的代码编写它:

    (async () => { // await has to be inside async function, anonymous in this case
      await sayHi() 
      sayBye()
    })()
    
    async function sayHi() {
      return new Promise(function (resolve) {
        $("#myOutput").text('hi');
        setTimeout(function() {
          resolve()
        }, 1000)
      });
    }
    
    async function sayBye() {
      $("#myOutput").text('bye');
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="myOutput"></div>

    【讨论】:

    • 在这个答案中,为什么 sayHi 和 sayBye 函数本身必须是异步的?看来您的匿名函数是唯一需要异步的函数。
    【解决方案4】:

    使用Promise方式

    sayHi() 
        .then(sayBye);
    
    function sayHi() {
        return new Promise(resolve => {
            setTimeout(()=> {
                $("#myOutput").text('hi'), resolve()
            }, 1000);
        })
    }
    
    async function sayBye() {
        $("#myOutput").text('bye');
    }
    

    或者像这样的sayHi

    async function sayHi() {
        await new Promise(resolve => {
            setTimeout(()=> {
                $("#myOutput").text('hi'), resolve()
            }, 1000)
        })
    }
    

    【讨论】:

      【解决方案5】:

      使用 async/await 是一种以完全可控的方式构建异步代码的绝佳方式。基于 Promise 的异步函数进入微任务存储库,该事件循环在普通 DOM 刷新/Web API 存储库中包含的事件和方法之前执行(例如 setTimeout())。但是,某些版本的 Opera 和 Firefox 浏览器将 setTimeout() 设置为优先于微任务存储库。无论如何,如果将基于 Promise 的函数与启用异步/等待的函数结合起来,则可以控制执行顺序。例如:

      // create function that returns Promise
      let hi = () => {
        return new Promise((resolve, reject) => {
          setTimeout(_ => {
            resolve('Hi '); // after 1500ms function is resolved and returns 'Hi '
          }, 1500);
        });
      }
      
      // create ordinary function that will return 'bye'
      let sayBye = () => {
        return 'Bye';
      }
      
      // create third function that will be async 'enabled', 
      // so it can use await keyword before Promise based functions
      let sayHi = async () => {
        let first = await hi();  // we store 'Hi ' into 'first' variable
        console.log(first);
        let second = sayBye(); // this execution will await until hi() is finished
        console.log(second);
      }
      
      // execute async enabled function
      sayHi();
      

      我们可以在 sayHi() 函数中添加 try / catch 块来控制 promise reject() 上的错误,但这超出了您的问题范围。

      祝你有美好的一天!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-10
        • 1970-01-01
        • 2019-10-21
        • 2020-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        相关资源
        最近更新 更多