js 异步 http 请求的返回值,如何赋值给一个变量? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
css3
V2EX    程序员

js 异步 http 请求的返回值,如何赋值给一个变量?

  •  
  •   css3 2020-10-24 21:56:08 +08:00 4448 次点击
    这是一个创建于 1816 天前的主题,其中的信息可能已经有所发展或是发生改变。

    异步编程新新新新手, 不应该说编程新手

    这几日在用 jsbox 构建一个自己的小工具,卡在了 http 异步请求这一块,请求返回值死活无法赋值给一个全局的变量给其他地方使用;

    了解了异步的一些基础用法,有通过 then 获取的,有通过定义 async 函数获取的,还有回调函数获取的 但发现有个特点就是拿到的返回值,作用域均仍在内部,拿不出来这个返回值

    // 调用 v 站的 api 例子,获取最新主题 function test() { var result = undefined let url = "api/topics/latest.json" return $http.get({ url: url }).then(resp => { var data = resp.data[0]['title'] return data }) } 
    //调用的获取返回值 async function getRet(){ var ret = await test(); console.log(ret); return ret; } getRet() // 拿不到 ret 的值 
    第 1 条附言    2020-10-26 11:05:08 +08:00

    还是交待一下上下文吧,我的原始需求: 我在jsbox中构建一个webview视图

    // 视图层 views: [ { type: "label", props: { text: "", url: test() // 这个位置需要用到http异步请求的返回值 }, events: { tapped: function() { $app.close(0); } } } 

    定义的请求http接口的函数 :

    // 逻辑层 function test() { var result = undefined let url = "api/topics/latest.json" return $http.get({ url: url }).then(resp => { var data = resp.data[0]['title'] return data }) } 

    在视图层,我应该如何把test的返回值传递过去?正确的做法是什么?

    25 条回复    2020-10-27 21:50:34 +08:00
    Yumwey
        1
    Yumwey  
       2020-10-24 21:57:34 +08:00 via Android
    async/await 返回的是 promise,所以,知道怎么拿了吗?
    kuanng
        2
    kuanng  
       2020-10-24 22:00:24 +08:00
    getRet 这个函数返回的是一个 promise 吧
    Jirajine
        3
    Jirajine  
       2020-10-24 22:12:13 +08:00 via Android
    异步就是这样的啊,你要非要用同步的风格写异步,那就把代码逻辑包在一个 async IIFE 里面,像这样
    (async function(){
    // your code here
    })()
    然后用 await 就能拿到包在 promise 里面的值了。

    还有个极其不推荐的办法是定义一个全局变量,然后异步代码里把结果赋值给这个变量,但你无法保证你取用这个变量的代码被调度到后面执行。
    css3
        4
    css3  
    OP
       2020-10-24 22:13:51 +08:00
    @css3 @Yumwey @kuanng
    这样可以,但我后面要用这个返回值的地方,是构建一个 webvirw, 它是不支持直接给一坨东西的,还是得赋值给变量才能用啊
    https://gist.github.com/seryte/e725987b2b18ccb43772a2b8ea182198
    vision1900
        5
    vision1900  
       2020-10-24 22:20:27 +08:00
    你写 test 的时候就已经拿到了值,只是这个是异步的
    无论你怎么封装,都不可能用同步的方式拿到值
    async/await 是一层语法糖,只是写起来像同步的而已,实际还是依赖 promise 。也就是说实际还是异步代码

    getRet() 运行的上下文是同步的,一开始方向就搞错了,陷入了“封装陷阱”
    css3
        6
    css3  
    OP
       2020-10-24 22:22:54 +08:00
    @vision1900 非常的对,我已经陷入封装循环了,还跳不出来异步这个“坎”
    css3
        7
    css3  
    OP
       2020-10-24 22:23:36 +08:00
    @Jirajine 尝试过,不行的,取不到
    css3
        8
    css3  
    OP
       2020-10-24 22:23:58 +08:00
    @vision1900 所以,我怎么用同步的方法拿到异步的返回值?
    Yumwey
        9
    Yumwey  
       2020-10-24 22:32:55 +08:00 via Android
    你非要同步的话,又不想再套 async/await 走逻辑的话,那就写个 emit
    9LCRwvU14033RHJo
        10
    9LCRwvU14033RHJo  
       2020-10-24 22:36:21 +08:00
    @css3

    异步代码赋给全局变量。同步代码这边 setInterval,然后不断重试最后总能取到。
    Jirajine
        11
    Jirajine  
       2020-10-24 22:38:55 +08:00 via Android
    @css3 你还是没看我在说什么。
    把所有代码都包进去,如果用全局变量赋值的话,很可能你后面取用的代码会先于你给全局变量赋值的异步代码执行,所以你会“取不到”,因为你取的时候还没赋值呢。这就是异步。
    vision1900
        12
    vision1900  
       2020-10-24 22:53:35 +08:00   3
    @css3 没有办法,同步代码不可能立即获得异步的返回,只能等待环境(浏览器或者 Node )告诉你异步代码执行结束了,你才能真正“拥有”返回值. 处理返回,要不用回调函数,要不用 Promise


    var result = undefined
    let url = "https//www.v2ex.com/api/topics/latest.json"
    return $http.get({
    url: url
    }).then(resp => {
    var data = resp.data[0]['title']
    // 这里你获得了返回,直接用就完了
    })

    如果你需要封装成函数让代码看起来更模块化,可以传一个回调函数
    funtion test(callback) {
    var result = undefined
    let url = "api/topics/latest.json"
    return $http.get({
    url: url
    }).then(resp => {
    var data = resp.data[0]['title']
    callback(data);
    })
    }

    function useData(data) {
    // 任何依赖于异步返回的代码都放这里
    console.log(data)
    }

    test(useData);

    // 高级一点的做法是返回一个 Promise
    funtion test() {
    var result = undefined
    let url = "api/topics/latest.json"
    return $http.get({
    url: url
    }).then(resp => {
    var data = resp.data[0]['title']
    return data; // .then 返回类型是 Promise,这个 Promise 会 resolve 为 .then 里的函数返回值
    })
    }

    test().then(data => {
    // 任何依赖于异步返回的代码都放这里
    console.log(data)
    })

    // 再高级一点是用 async/await,不过心里要明白,async/await 只是语法糖,实际还是 promise 。之所以高级是因为视觉上像同步代码,增强了可读性
    funtion test() {
    var result = undefined
    let url = "api/topics/latest.json"
    return $http.get({
    url: url
    }).then(resp => {
    var data = resp.data[0]['title']
    return data
    })
    }

    async main() {
    const data = await test();
    // 任何依赖于异步返回的代码都放这里
    console.log(data)
    }

    main();
    hazyzh
        13
    hazyzh  
       2020-10-24 23:18:57 +08:00   2
    我怎么用同步的方法拿到异步的返回值?

    ???
    这个问题问的非常好!这需要利用量子力学的一个概念 **协变量子场**, [空间和时间都不是连续的,宇宙时间,世界的一切,包括时空,都只是协变量子场的表现形式] 。

    建议你研究一下这个,这个问题一解决 可以从根本上一举攻克 js 回掉地狱的历史性难题。
    autoxbc
        14
    autoxbc  
       2020-10-24 23:26:14 +08:00
    异步是语言级的特性,没有「不支持这样的格式」的说法
    GzhiYi
        15
    GzhiYi  
       2020-10-24 23:57:31 +08:00
    关键字是:宏任务和微任务
    aaronlam
        16
    aaronlam  
       2020-10-25 02:07:50 +08:00
    你应该要把需要用到这个 await 返回的值的操作直接就写在 await 之后,这是最简单的办法了。因为 async await 说白了其根本就是 promise,你可以理解为 await 之后的代码还原成 promise 之后,就是在 then 里面的代码。

    ``` Javascript
    new promise((resolve, reject)=>{...}).then((value)=>{ // await 之后的代码就是类似在这里的代码!!] })。
    ```

    要是你非要把 then 里的 value 拿出来(但是按照我的理解,貌似这样有点脱裤子放屁的感觉),那按照你目前提供的代码,可以在外部写一个类似下面 getAsyncReturnValue 的函数

    ``` Javascript
    function getAsyncReturnValue(value)
    {
    // 这里做你要拿到 value 后要做的事
    }

    function test() {
    var result = undefined
    let url = "api/topics/latest.json"
    $http.get({
    url: url
    }).then(resp => {
    var data = resp.data[0]['title']
    return data
    })
    }

    (async ()=> {
    const value = await test();
    getAsyncReturnValue(value)
    }())
    //调用的
    ```
    kwrush
        17
    kwrush  
       2020-10-25 0:20:58 +08:00   1
    想要同步获取异步结果,那可以自己实现一个简单的 event emitter 或者观察者模式,比如
    class MyEmitter () {
    constructor() {
    this._events = [];
    }

    on = (event, listener) => {
    if (this._events[event] == null) {
    this._events[event] = [];
    }
    this._events[event].push(listener);
    }

    removeListener = (event, listener) => {...}
    emit = (event, data) => {
    if (this._events[event] == null) {
    throw new Error('no event found');
    }

    const fun = (listener) => listener(data);
    this._events[event].forEach(fun);
    }
    }

    const emitter = new MyEmitter();

    // 你要使用数据的地方
    emitter.on('getRes', (res) => console.log(res));
    ...

    const getRes = async () => {
    const res = await yourAsyncFun();
    emitter.emit('getRes', res);
    }

    await getRes();
    shenyu1996
        18
    shenyu1996  
       2020-10-25 10:26:11 +08:00 via Android
    await 变同步 或者放在异步的回调里
    Arrowing
        19
    Arrowing  
       2020-10-25 11:35:17 +08:00 via Android
    把.then 及其后面的代码删掉
    Doracis
        20
    Doracis  
       2020-10-26 08:55:22 +08:00
    请求回来的 result,用方法调用,作为形参,这样试试?
    ...then((res) => {
    this.anotherFunc(res)
    })
    css3
        21
    css3  
    OP
       2020-10-27 15:48:55 +08:00
    css3
        22
    css3  
    OP
       2020-10-27 15:51:00 +08:00
    @vision1900
    @aaronlam
    @kwrush
    @Doracis
    @Arrowing
    @shenyu1996
    大佬帮忙看一下,我 append 了原始需求
    Arrowing
        23
    Arrowing  
       2020-10-27 17:34:20 +08:00
    ```Javascript
    function test() {
    var result = undefined
    let url = "api/topic/latest.json"
    let res = $.get({ // 假设支持 jQuery,V2ex 控制台下可测试
    url: url,
    async: false // 使用同步请求
    })
    return res.responseJSON[0]['title']
    }
    ```
    css3
        24
    css3  
    OP
       2020-10-27 21:21:08 +08:00
    @Arrowing jsbox 中,加了 async: false,拿到的 res.responseJSON[0]['title'] ,还是个 Pormise
    css3
        25
    css3  
    OP
       2020-10-27 21:50:34 +08:00
    罢了罢了,解决不了放弃了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5132 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 38ms UTC 09:38 PVG 17:38 LAX 02:38 JFK 05:38
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86