JS 如何等待异步函数返回之后在return?

BigPolo
  • 89

如下代码 content 需要 b获取到之后再被复制,希望return 回的是请求后的值

const  bar= () => {
    let content = null

    async function getContent() {
        let b = await request()
        content = b
    }
    getContent()
    return content
}
回复
阅读 1.6k
3 个回答

异步通常是比较耗时的操作,使用异步就是为了不被耗时操作阻塞。所以异步调用有两个特点:

  • 异步调用不阻塞当前过程,如果异步调用后立即 return,不能拿到异步调用的结果(都还没执行完,哪来的结果)
  • 异步调用结束时间不确定,不能等他调用完成之后再执行 XX 代码,只能先把要作的事情准备好,告诉它完成调用之后执行(回调)

关于异步的内容,请参阅:异步编程需要“意识”

不过,由于异步调用比较“绕脑”,所以有一些语法糖来处理异步,比如 await 语法。使用 await 语法可以像写同步代码一样写异步代码,其实际的处理过程是编译/解释器来翻译的(简单地说可以理解为把 await 语句后的部分封装成一个回调,在 await 的异步调用完成之后执行)。

关于 await 的内容,请参阅:理解 JavaScript 的 async/await

如果想在同步代码中等待异步完成 —— 这个问题得想清楚,确实是想用“阻塞”的方式来等待,那可以用一个循环,不断的检查异步结果,直到拿到结果为止。不过 JavaScript 没有类似 sleep 的函数,所以一直循环会非常消耗 CPU。关键是 JavaScript 是单线程事件循环模式,很容易造成死锁。一般不会有人干这种事情。


问题中,bar 只能是异步,要么返回 Promise,要么使用回调处理后面业务。相对简单的是用 async 封装 Promise

const bar = async () => {
    let content = null;

    async function getContent() {
        let b = await request();
        content = b;
    }
    await getContent();
    return content;
};


bar().then(....) // 后续业务写在 then() 中

当然这达不到你封装 bar 的意愿。从这个用例里来看,不管是封 bar,还是封 getContent,都没有起到任何作用(getContent() 里如果还有其他逻辑另说),整个代码简化出来其实就是 request(),外面的业务仍然是使用 await request() 或者 request().then() 来处理,跟封装后的 await bar() 或者 bar().then() 完全没区别。

你可以试试循环等待 content 的代码,很大概率会直接锁死拿不到结果。

结论:还是打消异步转同步的想法,直接写异步代码嘛。

不能。

异步是具有传染性的,一旦异步,都得异步。所以你只能把 bar 也改成异步的。

如楼上所言,只能把 bar 也改成异步函数:

const  bar = async () => {
    async function getContent() {
        return await request();
    }
    return getContent();
}

如果把 request 的实现给改成 XHR ,倒是可以使用 sync 请求,不过期间的阻塞将是难以承受之痛。

你知道吗?

宣传栏