V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
luffy
V2EX  ›  程序员

JS axios async/await 好像只能返回 promise

  •  
  •   luffy · 2022-07-27 19:57:53 +08:00 · 3863 次点击
    这是一个创建于 850 天前的主题,其中的信息可能已经有所发展或是发生改变。
    async function hello() {
      return await Axios.request(options)
    }
    

    有办法返回最终值嘛? 而不是返回一个 promise

    如果是在服务端,比如 nodejs 里面,如果想要返回一个 axios request 后的值给客户端

    一般怎么处理的?

    30 条回复    2023-03-25 11:05:39 +08:00
    zhuangzhuang1988
        1
    zhuangzhuang1988  
       2022-07-27 19:59:58 +08:00
    没有办法。
    xiangyuecn
        2
    xiangyuecn  
       2022-07-27 20:03:18 +08:00
    这娃没救了,不知道加 async
    AyaseEri
        3
    AyaseEri  
       2022-07-27 20:08:09 +08:00
    调用函数里也 await 不就行了
    pagxir
        4
    pagxir  
       2022-07-27 20:18:47 +08:00 via Android
    这是异步调用。你是没有办法在单线程的 nodejs 直接转成同步调用的。要么多线程,要么去 hack 到 nodejs ,要么就只能继续异步调用。当然了,你可以换其他同步调用的实现
    pendulum
        5
    pendulum  
       2022-07-27 20:32:52 +08:00   ❤️ 1
    async 函数只能返回 promise
    elfive
        6
    elfive  
       2022-07-27 20:32:58 +08:00 via iPhone
    async 修饰你调用这个函数的函数,同时调用语句前面加 await 关键字
    或者调用的地方用.then 也行呀……
    eason1874
        7
    eason1874  
       2022-07-27 20:40:25 +08:00
    看样子你没理解 await ,你这样包一层再 let res = hello() 同样会拿到 promise

    你得在 async 里面 await 才能拿到返回值,比如

    async function hello() {
    let res = await Axios.request(options)
    // 这个 res 是同步返回值
    }

    要觉得调用 hello() 麻烦也可以把它写成立即执行的匿名函数
    jinliming2
        8
    jinliming2  
       2022-07-27 22:44:48 +08:00
    JS 是单线程,Promise 只能由 Runtime 去后台执行然后安排回调。
    如果你硬要同步的话,由于单线程,在等待 IO 响应的时候,其他所有代码都没办法跑。
    cz5424
        9
    cz5424  
       2022-07-27 22:45:01 +08:00
    直接去掉 async 不行吗?
    learningman
        10
    learningman  
       2022-07-27 22:48:29 +08:00 via Android
    写个 spin lock ,强行把异步转成同步就好了捏
    aaronlam
        11
    aaronlam  
       2022-07-27 22:53:19 +08:00
    await 后面的函数调用返回的就是 promise
    bojackhorseman
        12
    bojackhorseman  
       2022-07-27 22:55:38 +08:00 via iPhone
    因为它只是语法🍭,本质还是异步的
    yjd
        13
    yjd  
       2022-07-28 01:29:05 +08:00
    var getData;
    (() => {
    (async () => {
    await Axios.request(options)
    .then(res => getData = res.data)
    })();
    return getData;
    })();
    DiamondYuan
        14
    DiamondYuan  
       2022-07-28 01:43:39 +08:00   ❤️ 1
    有办法。 以下都前端黑魔法,不建议使用。 在某些特殊情况下有奇效。



    1. 在 nodejs 里可以使用 node-force-sync


    const { forceSync } = require('node-force-sync');

    const asyncGet = async (url: string) => {
    const axios = require('axios');
    return (await axios.get(url)).data;
    };

    const syncGet = forceSync(asyncGet);

    const response = syncGet('https://postman-echo.com/get?foo=bar');


    2. 在浏览器里可以使用


    $.ajax({
    type: "GET",
    url: remote_url,
    async: false
    })
    nowheremanx
        15
    nowheremanx  
       2022-07-28 03:28:42 +08:00
    等 axios 调用完之后返回客户端不就好了,也就是 then 或者 await 。
    chnwillliu
        16
    chnwillliu  
       2022-07-28 04:22:29 +08:00 via Android
    开一个 worker 然后 shared memory, 然后用 Atomics.wait 挂起等待 worker 完成请求。。。。
    geelaw
        17
    geelaw  
       2022-07-28 05:09:50 +08:00
    这个问题和 axios 没有任何关系,JavaScript 不允许同步化异步操作,而且只要 JavaScript 维持单线程模型和 setTimeout 的语义,很难预见同步化异步操作的可能性。

    考虑如下代码:

    var Axios = {};
    Axios.request = function (options) {
    return new Promise(function (resolve, reject)
    {
    setTimeout(function () {
    console.log(2);
    resolve(3);
    }, 1000);
    });
    };

    考虑强行同步

    var mySync = function (options)
    {
    return magic syncronous result of Axios.request(options);
    };

    那么代码

    var excl = mySync();
    console.log(1);
    console.log(excl);

    有矛盾。

    一方面,根据 Promise 和 setTimeout 的要求,2 必须在 1 之后( Promise 构造器传入的方法立刻执行,因此 setTimeout 发生在 1 之前,同时 setTimeout 在延迟是 1000 的时候保证传入的方法在当前同步代码块结束后才调用)。另一方面,如果要求 excl 得到 3 的值,那么必须先经过 2 ,但 excl 的值在 1 之前得到。

    @DiamondYuan #14 应该注意 node-force-async 得到的结果是错误的——例如传入的方法必须不读取外 scope 的内容,并且返回值会失去类型——这是因为它的原理是同步开一个新的进程执行代码。第二个方法里面是直接从源头杜绝异步。
    JounQin
        18
    JounQin  
       2022-07-28 07:02:44 +08:00 via iPhone
    Node 端可以用这个 https://github.com/un-ts/synckit
    最近在考虑增加浏览器端端支持。
    JounQin
        19
    JounQin  
       2022-07-28 07:05:02 +08:00 via iPhone
    node-force-sync 用的 child_process 完全不用考虑。
    fds
        20
    fds  
       2022-07-28 07:45:54 +08:00
    ```
    async function hello() {
    let res = await Axios.request(options)
    将 res 发送给客户端
    }
    ```
    ming159
        21
    ming159  
       2022-07-28 08:25:57 +08:00
    一堆人费劲心思提出了这么个 Promise 规范,解决异步带来的麻烦, 然后你要在这基础上硬生生的在退回原始方式....
    wangtian2020
        22
    wangtian2020  
       2022-07-28 08:35:05 +08:00
    JavaScript 异步函数 async function 重新学吧
    https://zh.javascript.info/async-await

    promise 是回调地狱的优雅解决方法
    DOLLOR
        23
    DOLLOR  
       2022-07-28 09:11:02 +08:00
    const result = await hello();
    response.end(result);
    yunyuyuan
        24
    yunyuyuan  
       2022-07-28 09:27:52 +08:00
    nothingistrue
        25
    nothingistrue  
       2022-07-28 09:34:29 +08:00
    同步方法才能直接返回最终值,异步方法只能返回 promise 或者类似机制,你要想让异步方法产生返回最终值的效果,那就要使用“异步回同步”处理(起的名字可能不对)。

    这个“异步回同步”处理,对于多线程语言或者允许当前线程阻塞的环境来说,可以给 promise 设计个带 wait/await 的方法,调用它就能立刻(在当前线程)同步阻塞的等待返回值,例如 Java 的 java.util.concurrent.Future#get() 。而在 async/await 设计理念下,你可以通过 await 调用异步方法来获取返回值,就是你代码里面的 return await Axios.request(options) ,但是这个调用必须是在 async 下的,因为要不是在 async 下那么你就是在主线程中,这时候是不允许阻塞的。
    jspatrick
        26
    jspatrick  
       2022-07-28 16:25:47 +08:00
    async 具有传染性,这是他的优点,也是他的缺点
    DingJZ
        27
    DingJZ  
       2022-07-28 17:36:10 +08:00
    顺着这看了一下 node-force-sync 的实现,真有想法啊,鬼才
    chnwillliu
        28
    chnwillliu  
       2022-07-28 20:21:18 +08:00 via Android
    @nothingistrue js 也有的,不过不是线程,是 worker ,更像是进程就是了,而且没法直接共享内存,要借助 shared buffer, 但也是可以以阻塞模式 wait 对方,等对方 notify 再继续跑的。也就是借助 Atomics 相关的 API 。一些库可以利用这个把复杂异步操作封装进另一个 worker ,对外呈现同步阻塞的调用方式,很有意思。
    amlee
        29
    amlee  
       2022-07-28 22:39:45 +08:00
    hello().then(result => console.log(result))
    ScottHU
        30
    ScottHU  
       2023-03-25 11:05:39 +08:00
    不行,async 函数里不管返回什么东西,调用的地方永远只能接收到 promise ,如果你觉得这样麻烦或不直观,可以尝试一下和 react 、vue 等 UI 框架深度融合的请求库,可以解决你这个问题,推荐给你使用 alova ,api 设计和 axios 很相似
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2010 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 00:55 · PVG 08:55 · LAX 16:55 · JFK 19:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.