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

JS 异步的一个问题

  •  
  •   azcvcza · 2020-02-27 12:35:39 +08:00 · 3318 次点击
    这是一个创建于 1729 天前的主题,其中的信息可能已经有所发展或是发生改变。

    困扰了很久的异步问题 一般来说,想要 JS 程序顺序执行,会借助 Promise 的链式结构来顺序调用程序

     new Promise(resolve => {
    	Afunc();
    	resolve(any);
     }).then( res=>{
    	Bfunc();
     })
    

    现在我想要做更复杂一点的事,例如 Afunc 里是 react 组件里的一个发请求并 setState 的函数

    Afunc = () =>{
      axios.post(`xxx`,{params}).then(res=>{
        if(res.xxxx === 'xxxx'){
    	 this.setState({},callBackFunc);
    	}
      })
    }
    

    我有一些业务函数(操纵 UI,脏代码)要在 setState 之后才做,也就是塞在 callBackFunc 里 显然

     new Promise(resolve=>{
    	Afunc();
        resolve // resolve 之后不知道多少个 then 才执行 Afunc 里的 .then(res=>{...})
    })
    

    不满足我新产生的想法。因为 resolve 的时候 Afunc 只跑到 post, .then 里的代码还没轮到 那么我的问题是,如何在不往 Afunc 里塞 callback 的实现一个可以操控的事件流 我现在的做法

    Afunc = (callback) =>{
    	...
        this.setState({},()=>{
        	callback && callback();
        })
    }
    

    《 You don't know JS 》里看到的好像是 setTimeout 和 promise 混用的时候,把 resolve 给塞到 setTimeout 中的函数 promise((solve)=>{setTimeout(()=>{func, resolve},1000)}


    P.S.(如果要手动实现事件队列那还是算了)


    P.S. async/await generator 这些也基于 Promise 的语法糖,真的会有用吗?

    18 条回复    2020-02-28 18:54:26 +08:00
    AlphaTr
        1
    AlphaTr  
       2020-02-27 12:43:23 +08:00 via iPhone   ❤️ 1
    把 Afunc 包装成 promise
    maichael
        2
    maichael  
       2020-02-27 12:44:04 +08:00   ❤️ 1
    大概能这么干,但我没有实测。

    Afunc = async () => {
    const res = await axios.post(`xxx`, {params})
    if(res.xxxx === 'xxxx') {
    retrun new Promise(resolve => this.setState({}, resolve))
    }
    }

    用的时候直接

    await Afunc()
    otherFunc()

    或者

    Afunc().then()
    crysislinux
        3
    crysislinux  
       2020-02-27 13:03:37 +08:00   ❤️ 1
    2 楼的办法就可以了
    kof21411
        4
    kof21411  
       2020-02-27 13:06:53 +08:00   ❤️ 1
    2 楼方法正确,async/await 异步变同步
    azcvcza
        5
    azcvcza  
    OP
       2020-02-27 13:33:32 +08:00
    @maichael 和我之前的想法很像,不过如果把 async 打开的话,实际上也是在往 setState 里塞回调
    当然这种写法很简洁,受教了
    aaronlam
        6
    aaronlam  
       2020-02-27 13:39:46 +08:00
    我现在在项目里基本上用 async await 就能解决很多异步顺序执行的问题
    love
        7
    love  
       2020-02-27 16:46:29 +08:00
    async/await 直观多了,虽然可以做的事回调和 promise 都能做
    TheCZ
        8
    TheCZ  
       2020-02-27 17:36:17 +08:00
    这个帖子需要 马克一下 最近遇到同样的疑惑!
    FaiChou
        9
    FaiChou  
       2020-02-27 18:22:56 +08:00   ❤️ 1
    @azcvcza #5 「我有一些业务函数(操纵 UI,脏代码)要在 setState 之后才做,也就是塞在 callBackFunc 里」显然就需要在 setState({}, callback) 塞回掉了,避免不了的。

    所以你的问题答案是:

    return new Promise(r => this.setState({}, r))
    mmdsun
        10
    mmdsun  
       2020-02-27 18:35:22 +08:00 via Android   ❤️ 1
    async/await 可以看一下 msdn 异步文档。async/await 和 Rx 系列,最早都是微软搞出来模型。官方文档很全面。

    然后对比学习 coroutine stackful。js 的 async/await 和 fibjs,还有 c#的 async/await,go 的 goroutine。这样异步就不会有什么问题了。
    azcvcza
        11
    azcvcza  
    OP
       2020-02-27 21:03:48 +08:00
    @FaiChou 我想了很久,除了塞回调之外,好像没办法精确区分出 setState 和 then 里哪个更快
    azcvcza
        12
    azcvcza  
    OP
       2020-02-27 21:08:03 +08:00
    @mmdsun 实际上 js 里的 async/await 是包了一层 promise 在里边,我其实真正想知道的是,除了 async/await,和 promise 这系列的顺序流操纵之外,除了往函数参数里塞回调,是不是还会有其他一些通用的,确定异步函数完成时机的东西。当然我自己翻 js 高程,you don‘t know js 没找到这么细的,you don't know 里提到最接近的就是 promise 里塞一个 setTimeout,在 setTimeout 里 resolve 了。生成器看是看了,但平常用的太少
    Vogan
        13
    Vogan  
       2020-02-27 21:19:34 +08:00
    @azcvcza #12 没有了。js 就是这么奇葩。事件循环的机制在那里,别想歪门邪道。
    duan602728596
        14
    duan602728596  
       2020-02-28 00:41:56 +08:00
    class Com extends React.Component {
    state = { data: [] };

    changeData(data) {
    return new Promise((resolve, reject) => {
    this.setState({ data }, resolve);
    });
    }

    async getData() {
    const res = await fetch(url);
    const data = await res.data.json();

    await this.changeData(data);
    // 之后要做的事情
    }

    componentDidMount() {
    this.getData();
    }
    }

    根据你的意思写的模拟的代码,就这个意思?
    StrayBugs
        15
    StrayBugs  
       2020-02-28 01:48:24 +08:00 via Android
    你想的方向不对

    > 我有一些业务函数(操纵 UI,脏代码)要在 setState 之后才做

    react 何时应用更新 states 是不可知的,那么这些副作用应该放到生命周期或者 effect hooks 中处理。
    StrayBugs
        16
    StrayBugs  
       2020-02-28 02:07:48 +08:00 via Android
    好吧,才发现 setState callback 也是安全的,这么用得比较少,补了个盲点。那么 2 楼是正解。
    azcvcza
        17
    azcvcza  
    OP
       2020-02-28 18:53:29 +08:00
    @Vogan 好吧
    azcvcza
        18
    azcvcza  
    OP
       2020-02-28 18:54:26 +08:00
    @duan602728596 差不多是这样,你的拆分看起来合适,但本质上还是往里边塞回调了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2705 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 15:19 · PVG 23:19 · LAX 07:19 · JFK 10:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.