V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Hopetree
V2EX  ›  Vue.js

vue 的 computed 相关的一个问题,求助

  •  
  •   Hopetree ·
    Hopetree · 2019-09-02 23:19:18 +08:00 · 7709 次点击
    这是一个创建于 1668 天前的主题,其中的信息可能已经有所发展或是发生改变。

    但愿这个图能显示

    情况如图所示,这个计算属性会在 sctext 变动时触发,实际上也的确会这样,但是我在 HTML 中使用{{ suggestion }}发现是空的,但是 console 日志会刷新值,所以很奇怪,为甚返回不到值?

    如果图挂了,看源码:

    <template>
        <div>
        	...	方便查看所以省略其他
            <p>{{ suggestion }}</p>
        </div>
    </template>
    
    <script>
    export default {
        data() {
            return {
                // 从 store 里面读取数据并使用
                sctype: "",
                scdata: {},
                sctypelist: [],
                sctext: "",
            };
        },
        created() {
            // 设置默认值
            var default_type = this.$store.getters.searchTypes[0];
            this.sctype = default_type;
            this.sctypelist = this.$store.getters.searchTypes;
            this.scdata = this.$store.state.searchList[default_type];
        },
        computed: {
            suggestion: function() {
                var a = ''
                this.$axios
                    .get("/baidu/su", { params: { wd: this.sctext } })
                    .then(ret => {
                        var json_str = ret.data.match(/s:(\[.*\])}\);/);
                        if (json_str) {
                            var json_str = json_str[1];
                        }
                        console.log(json_str);
                        a = json_str
                    });
                return a
            }
        },
        methods: {
            // 选择表单变化的时候同步数据
            changedata: function(command) {
                this.sctype = command;
                this.scdata = this.$store.state.searchList[command];
            }
        }
    };
    </script>
    
    <style scoped>
    img {
        width: 1.2rem;
        margin: 0rem 0.2rem -0.2rem 0rem;
    }
    </style>
    
    
    42 条回复    2019-09-03 17:05:36 +08:00
    murmur
        1
    murmur  
       2019-09-02 23:24:26 +08:00
    promise 是异步请求啊,你这个问题不懂的话建议先搞一下 promise 是个什么东西
    既然是异步 ajax 那返回也应该是一个 promise 才对
    murmur
        2
    murmur  
       2019-09-02 23:26:39 +08:00
    老老实实用 method 绑事件不好么 看你是搜索提示 这个建议直接用定时器检测改动 你不知道中文输入法有什么坑
    然后 a 做成 data 里的变量 检测到有文字输入就搜 搜了在 then 里赋值给 a suggestion 那里就是 a 了
    xxx749
        3
    xxx749  
       2019-09-02 23:28:37 +08:00 via Android
    亲亲,这边建议您用 Watch 呢,您这边另起一个属性把 GET 拿到的数据赋值给这个属性就行了呢
    krisfive
        4
    krisfive  
       2019-09-02 23:28:54 +08:00
    emmm 楼上 +1
    hahasong
        5
    hahasong  
       2019-09-02 23:30:19 +08:00
    计算属性里套 ajax,令人窒息的操作。ajax 还没结束。空的 a 就被返回了
    Allianzcortex
        6
    Allianzcortex  
       2019-09-02 23:33:32 +08:00
    像是 async 和 await 的问题,因为 axios 返回的数据没有被用到,所以会 先 return 再 console.log(). 这里提一个 fix 的方法,把 return a 放到 resolvoe 函数里,楼主可以试下:

    var a = ' '

    a = this.$axios.get(...).then(... return json_str)
    ochatokori
        7
    ochatokori  
       2019-09-02 23:33:47 +08:00 via Android   ❤️ 1
    建议先学习 js 异步的概念…

    这样说吧,你这个代码的执行顺序是
    var a='' //赋值,没问题
    axios //哦?这个是异步的,先发请求,结果丢一边等我有空再说
    return a//a 还空着,就被 computed 出去了
    //刚才有个异步还没处理,现在轮到你了
    //得到结果,给 a 赋值,这个时候 a 当然有值,但是 computed 方法早就跑完了
    //这里的流程实际上有问题,为了方便理解我省去了微任务和宏任务那些东西… promise 是微任务(面试要考)
    Hopetree
        8
    Hopetree  
    OP
       2019-09-02 23:37:38 +08:00
    @murmur
    @xxx749
    我现在是这样,的确能拿到返回值了,但是由于增加了一个属性,所以每次改动输入,都会重复调用 2 次接口,我还是看看你推荐的 watch 吧

    @hahasong 因为我是在学 vue,想着尽量用更多的插件来实现功能,都是为了探索
    CDL
        9
    CDL  
       2019-09-02 23:38:41 +08:00
    computed 只会监听 data,prop 这类属性值
    Allianzcortex
        10
    Allianzcortex  
       2019-09-02 23:38:45 +08:00
    @Allianzcortex 最后还要再 return a,其实是[因为要用到返回的结果]所以能保证[等到 axios 请求结果出来后再返回 computed 的结果]
    Hopetree
        11
    Hopetree  
    OP
       2019-09-02 23:55:05 +08:00
    @xxx749 非常感谢,我刚看了一下 watch,发现这个才是我需要的方法,已经实现了效果,下面是我改的

    ```
    watch: {
    sctext(val) {
    this.$axios
    .get("/baidu/su", { params: { wd: this.sctext } })
    .then(ret => {
    var json_str = ret.data.match(/s:(\[.*\])}\);/);
    if (json_str) {
    var json_str = json_str[1];
    }
    console.log(json_str);
    this.suggestion = json_str
    });
    }
    },
    ```
    Allianzcortex
        12
    Allianzcortex  
       2019-09-03 00:00:57 +08:00
    @ochatokori 我理解的流程也是这样的,那么这个 fix 方法理论上应该可以?
    karnaugh
        13
    karnaugh  
       2019-09-03 00:10:17 +08:00
    天秀。。。。
    lqzhgood
        14
    lqzhgood  
       2019-09-03 00:16:08 +08:00 via Android
    用 watch 要 debounce
    不然你就是 ddos
    Allianzcortex
        15
    Allianzcortex  
       2019-09-03 00:32:37 +08:00
    @ochatokori 算了,看了下,除了 await 外确实没有别的方法,就算是用变量也不行
    SilentDepth
        16
    SilentDepth  
       2019-09-03 08:31:44 +08:00
    @Allianzcortex #15 如果你是说要让这个过程「同步地」完成,强制循环等待法可解。只是,考虑到 JS 整体是单线程的,你的页面会被冻结(

    其实 computed 应对这种需求也不是没有用,只是直观上没那么方便。创建两个普通状态,loading 和 data,然后触发异步动作,首先 loading = true,异步返回后 loading = false 并把返回数据赋值给 data。计算属性同时访问这俩普通状态,当 loading === true 时返回占位内容,loading === false 时返回 data。因为 loading 的变化也会导致计算属性刷新,所以可以直接被模板使用。

    这些过程直接写到组件里会比较乱,所以用 Vue.obserable( ) 或 @vue/composition-api 是更好的做法。(是的我就是来安利 Vue 3 的~)
    VancleefL
        17
    VancleefL  
       2019-09-03 09:01:23 +08:00
    sctext 变动频繁吗?如果变动频繁记得加防抖..
    Zink99
        18
    Zink99  
       2019-09-03 09:02:09 +08:00
    同步任务执行完成后才执行 .then() 中的代码,所以 a 是空

    了解下异步?
    https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7
    meepo3927
        19
    meepo3927  
       2019-09-03 09:17:23 +08:00
    Ajax 异步 ,

    你 return a 的时候,a = json_str 还没有执行呢
    no1xsyzy
        20
    no1xsyzy  
       2019-09-03 09:17:24 +08:00
    @SilentDepth 阻塞式请求也是可以同步的,但也会冻结页面,不过 CPU 消耗比较少
    tumobi
        21
    tumobi  
       2019-09-03 09:21:39 +08:00
    还是使用 async await 吧
    no1xsyzy
        22
    no1xsyzy  
       2019-09-03 09:25:44 +08:00
    基础概念问题…… 附一个 2014 年的演讲:
    SilentDepth
        23
    SilentDepth  
       2019-09-03 09:27:49 +08:00
    @no1xsyzy #20 那个开关不是都被废弃了吗,没准哪天都不能用了(
    hyy1995
        24
    hyy1995  
       2019-09-03 09:34:24 +08:00
    你这个问题其实跟 vue 没啥关系,纯粹就是网络请求没请求完成前,你就 return 返回了,此时数据都还没取到,这就是个异步问题,太秀了吧。。。
    liuguang
        25
    liuguang  
       2019-09-03 09:38:04 +08:00
    因为这个是异步的,请求还没完成,就 return 了
    galikeoy
        26
    galikeoy  
       2019-09-03 09:45:40 +08:00
    计算属性嵌套异步请求,龟龟,骚操作
    jrtzxh020
        27
    jrtzxh020  
       2019-09-03 09:48:27 +08:00 via iPhone
    有个 asyncComputed 的库 可以了解一下
    lscho
        28
    lscho  
       2019-09-03 09:48:56 +08:00
    亲亲,建议您学习一下 js 噢
    mikoshu
        29
    mikoshu  
       2019-09-03 10:08:10 +08:00
    只想说一句 666 好歹把 return 写到 promise 里面呀
    Curtion
        30
    Curtion  
       2019-09-03 10:12:08 +08:00
    这是异步问题啊,和我初学 js 时犯的问题的一样,建议看看书巩固下基础
    mikoshu
        31
    mikoshu  
       2019-09-03 10:15:58 +08:00
    @mikoshu 就算 return 写到 promise 里 还得 return axios 然后返回一个 promise 估计也不好使 果然只能用 await 了 还有楼主改成 watch 的话 如果这个值变动很快 比如监听 input 的 input 事件 就得故意加延迟查询 不然请求太多
    Biwood
        32
    Biwood  
       2019-09-03 10:17:05 +08:00 via Android
    1 楼和 7 楼都已经说到点子上了,去了解一下 JavaScript 同步和异步的原理和机制,比乱猜乱尝试有意义多了。后面还一堆扯到 async await 的,到底是有多菜啊各位,学习框架就真的不用学底层和基础知识了吗
    tolking
        33
    tolking  
       2019-09-03 10:19:20 +08:00
    建议你打开项目的 eslint 或者配置下。这种情况就会直接提示
    ```
    Unexpected asynchronous action in "suggestion" computed property.eslint(vue/no-async-in-computed-properties)
    ```
    shintendo
        34
    shintendo  
       2019-09-03 10:36:55 +08:00
    上面说用 await 可以解决的各位,麻烦上个代码好吗?
    shintendo
        35
    shintendo  
       2019-09-03 10:37:12 +08:00
    @Biwood +1 我都惊了
    ljpCN
        36
    ljpCN  
       2019-09-03 10:55:05 +08:00 via Android
    楼主已经解决了,而且也很耐心地去寻求解决方案并尝试。不过还是想说,学 vue 之前,先学 js
    wunonglin
        37
    wunonglin  
       2019-09-03 11:06:26 +08:00
    这边建议 lz 先重新学习 vue 呢亲,async 也要另外学一下
    Sapp
        38
    Sapp  
       2019-09-03 12:48:17 +08:00
    我好久没用过 computed 了,但是我似乎记得,这个属性推荐的是做同步操作啊?你这个需求应该在坚挺某个输入的值变化,然后再调用请求,请求完成之后设置 this.a
    mamahaha
        39
    mamahaha  
       2019-09-03 13:02:06 +08:00
    你这个相当于是暗恋一个人,对方却不知道。
    johnnyNg
        40
    johnnyNg  
       2019-09-03 13:49:59 +08:00
    建议重学 js
    mikoshu
        41
    mikoshu  
       2019-09-03 17:02:58 +08:00
    @Biwood
    @shintendo
    emmm 确实是 估计大家一开始都没想那么多 以为直接给 suggestion 加 async 然后在 promise 的位置 await 一下 再 return 就好了 (包括我也是,已经是习惯把 await 当成是同步了,是有点想当然了)因为毕竟是语法糖 这样会导致 computed 根本无法使用
    supuwoerc
        42
    supuwoerc  
       2019-09-03 17:05:36 +08:00
    终于见到我会的问题了(滑稽)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5452 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 08:36 · PVG 16:36 · LAX 01:36 · JFK 04:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.