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

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

  •  
  •   Hopetree · 266 天前 · 4370 次点击
    这是一个创建于 266 天前的主题,其中的信息可能已经有所发展或是发生改变。

    但愿这个图能显示

    情况如图所示,这个计算属性会在 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   266 天前
    promise 是异步请求啊,你这个问题不懂的话建议先搞一下 promise 是个什么东西
    既然是异步 ajax 那返回也应该是一个 promise 才对
    murmur
        2
    murmur   266 天前
    老老实实用 method 绑事件不好么 看你是搜索提示 这个建议直接用定时器检测改动 你不知道中文输入法有什么坑
    然后 a 做成 data 里的变量 检测到有文字输入就搜 搜了在 then 里赋值给 a suggestion 那里就是 a 了
    xxx749
        3
    xxx749   266 天前 via Android
    亲亲,这边建议您用 Watch 呢,您这边另起一个属性把 GET 拿到的数据赋值给这个属性就行了呢
    krisfive
        4
    krisfive   266 天前
    emmm 楼上 +1
    hahasong
        5
    hahasong   266 天前
    计算属性里套 ajax,令人窒息的操作。ajax 还没结束。空的 a 就被返回了
    Allianzcortex
        6
    Allianzcortex   266 天前
    像是 async 和 await 的问题,因为 axios 返回的数据没有被用到,所以会 先 return 再 console.log(). 这里提一个 fix 的方法,把 return a 放到 resolvoe 函数里,楼主可以试下:

    var a = ' '

    a = this.$axios.get(...).then(... return json_str)
    ochatokori
        7
    ochatokori   266 天前 via Android   ❤️ 1
    建议先学习 js 异步的概念…

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

    @hahasong 因为我是在学 vue,想着尽量用更多的插件来实现功能,都是为了探索
    CDL
        9
    CDL   266 天前
    computed 只会监听 data,prop 这类属性值
    Allianzcortex
        10
    Allianzcortex   266 天前
    @Allianzcortex 最后还要再 return a,其实是[因为要用到返回的结果]所以能保证[等到 axios 请求结果出来后再返回 computed 的结果]
    Hopetree
        11
    Hopetree   266 天前
    @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   266 天前
    @ochatokori 我理解的流程也是这样的,那么这个 fix 方法理论上应该可以?
    karnaugh
        13
    karnaugh   266 天前
    天秀。。。。
    lqzhgood
        14
    lqzhgood   266 天前 via Android
    用 watch 要 debounce
    不然你就是 ddos
    Allianzcortex
        15
    Allianzcortex   266 天前
    @ochatokori 算了,看了下,除了 await 外确实没有别的方法,就算是用变量也不行
    SilentDepth
        16
    SilentDepth   265 天前
    @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   265 天前
    sctext 变动频繁吗?如果变动频繁记得加防抖..
    Zink99
        18
    Zink99   265 天前
    同步任务执行完成后才执行 .then() 中的代码,所以 a 是空

    了解下异步?
    https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7
    meepo3927
        19
    meepo3927   265 天前
    Ajax 异步 ,

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