JS 异步的一个问题

2020-02-27 12:35:39 +08:00
 azcvcza

困扰了很久的异步问题 一般来说,想要 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 的语法糖,真的会有用吗?

3303 次点击
所在节点    程序员
18 条回复
AlphaTr
2020-02-27 12:43:23 +08:00
把 Afunc 包装成 promise
maichael
2020-02-27 12:44:04 +08:00
大概能这么干,但我没有实测。

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

所以你的问题答案是:

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

然后对比学习 coroutine stackful。js 的 async/await 和 fibjs,还有 c#的 async/await,go 的 goroutine。这样异步就不会有什么问题了。
azcvcza
2020-02-27 21:03:48 +08:00
@FaiChou 我想了很久,除了塞回调之外,好像没办法精确区分出 setState 和 then 里哪个更快
azcvcza
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
2020-02-27 21:19:34 +08:00
@azcvcza #12 没有了。js 就是这么奇葩。事件循环的机制在那里,别想歪门邪道。
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
2020-02-28 01:48:24 +08:00
你想的方向不对

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

react 何时应用更新 states 是不可知的,那么这些副作用应该放到生命周期或者 effect hooks 中处理。
StrayBugs
2020-02-28 02:07:48 +08:00
好吧,才发现 setState callback 也是安全的,这么用得比较少,补了个盲点。那么 2 楼是正解。
azcvcza
2020-02-28 18:53:29 +08:00
@Vogan 好吧
azcvcza
2020-02-28 18:54:26 +08:00
@duan602728596 差不多是这样,你的拆分看起来合适,但本质上还是往里边塞回调了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/648004

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX