gpt4 book ai didi

javascript - 如何按顺序调用异步 Action 创建者?

转载 作者:行者123 更新时间:2023-11-30 20:51:58 26 4
gpt4 key购买 nike

源代码

索引.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import ReduxThunk from 'redux-thunk';
import reducer from './redux';

const body = document.querySelector('body'),
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose,
store = createStore(reducer, composeEnhancers(applyMiddleware(ReduxThunk)));

ReactDOM.render(<Provider store={store}><App/></Provider>, body);

App.js

import React from 'react';
import Shortcut from './Shortcut';

export default class App extends React.PureComponent {
render() {
return <Shortcut/>;
}
}

快捷方式.js

import React from 'react';
import { connect } from 'react-redux';
import { print_date_async } from './redux';

class Shortcut extends React.PureComponent {
componentDidMount() {
window.addEventListener('keydown', (event) => {
if (event.keyCode === 13) {
this.props.print_date_async({ date: new Date().toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1") });
}
});
}

render () {
return null;
}
}

function mapDispatchToProps(dispatch) {
return {
print_date_async: (date) => dispatch(print_date_async(date))
};
}

Shortcut = connect(undefined, mapDispatchToProps)(Shortcut);

export default Shortcut;

redux.js

import { createAction, handleActions } from 'redux-actions';

export const print_date = createAction('print_date');

export function print_date_async (payload) {
return async (dispatch) => {
try {
await wait_async();
dispatch(print_date({ date:payload.date }));
}
catch (exeption) {
console.error(exeption);
}
};
}

const initial_state = { };

export default handleActions({
print_date: (state, action) => {
console.log(action.payload.date);
return { ...state }
}
}, initial_state);

function wait_async (number) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, Math.floor(Math.random() * 10000)); // 0000 ~ 9999
});
};

问题

https://codesandbox.io/s/l7y4rn61k9

以我创建的程序为例进行说明,当您按下回车键时,您按下回车键的时间会在随机秒后输出。

我想在调用一个异步 Action 创建器之后调用下一个 Action 创建器。

如果按住回车键,第一次按下的结果也可以稍后打印。

01:42:48
01:42:48
01:42:47
01:42:47
01:42:47
01:42:47
01:42:48

我考虑过导出变量来检查状态,但我不喜欢它。我也不喜欢检查按键之间的间隔。

我想按照下面的方式来做,但是实现起来并不容易。如果你知道这件事,请回答。感谢阅读!

window.addEventListener('keydown', (event) => {
if (event.keyCode === 13) {
if (!this.proceeding) {
this.proceeding = true;
(async () => {
await this.props.print_date_async({ date: new Date().toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1") });
this.proceeding = false;
})();
}
}
});

解决

我只需要在使用 redux-thunk 时返回 promise 对象。

export function print_date_async (payload) {
return (dispatch) => new Promise(async (resolve, reject) => {
try {
await wait_async();
dispatch(print_date({ date:payload.date }));
resolve();
}
catch (exeption) {
console.error(exeption);
reject(exeption);
}
});
}

我知道 async() 返回 promise 对象,所以你不必用 promise 包装。

最佳答案

问题是您有一个用户输入流,它创建了一个异步值流。这些值可以按照与用户输入顺序不同的顺序解析。

例如:用户点击 A、B 和 C,这会创建 Promise A、B 和 C,但它们按 C、B 和 A 的顺序解析。您希望它们按与用户操作相同的顺序解析,对吗?

使用 promises 解析来排序或加入用户生成的流非常复杂,也许 Reactive x 可以解决这个问题,但下面的代码应该可以做到:

const resolveOrderedAndFast = (function(promiseInfos,requestIndex){
const lastCall = {};
return fastHandler => orderedHandler => promise => {
requestIndex++;
promise.then(fastHandler);
promiseInfos.push([promise,orderedHandler,requestIndex]);


//only resolve when it's last call
const last = () => {
lastCall.id={};
var check = lastCall.id;
return promise.then(
resolve=>
Promise.all(
promiseInfos
.sort((x,y)=>x[2]-y[2])
.map(([p,fn,requestIndex])=>{
return p.then(
([r,seconds])=>{
return [r,seconds,fn,requestIndex];
}
)
})
).then(
(resolves)=>{
if(check===lastCall.id){
resolves.forEach(
([r,seconds,fn,requestIndex])=>
fn([r,seconds,requestIndex])
);
promiseInfos=[];
requestIndex=0;
}else{
//ignore, no problem
}
}
)
);
};
last();//only resolve the last call to this function
};
}([],0))

const later = resolveValue => {
const values = ["A","B","C"];
const index = values.indexOf(resolveValue);
return new Promise(
(resolve,reject)=>
setTimeout(
x=>resolve([resolveValue,(4-(index*2))])
,(4-(index*2))*1000
)
)
};
const fastHandler = val => ([resolve,seconds])=>
console.log(
val,
"FAST HANDLER --- resolved with:",
resolve,
"in",seconds,"seconds"
);
const orderedHandler = val => ([resolve,seconds,i])=>
console.log(
"Call id:",
i,
"ORDRED HANDLER --- resolved with:",
resolve,
"in",seconds,"seconds"
);
const valueArray = ["A","B","C","A","B","C","A"];
console.log("making request:",valueArray);
valueArray
.forEach(
val=>
resolveOrderedAndFast
(fastHandler(val))
(orderedHandler(val))
(later(val))
);

setTimeout(
()=>
console.log("making more requests:",valueArray) ||
valueArray
.forEach(
val=>
resolveOrderedAndFast
(fastHandler(val))
(orderedHandler(val))
(later(val))
)
,500
);

这是一个更简单的版本,对它的作用有更多评论:

const Fail = function(reason){this.reason=reason;};
const resolveOrderedAndFast = (function(preIndex,postIndex,stored){
return fastHandler => orderedHandler => promise => {
//call this function before the promise resolves
const pre = p=> {
preIndex++;
p.then(fastHandler);
(function(preIndex,handler){//set up post when promise resolved
//add pre index, this will be 1,2,3,4
// but can resolve as 2,4,3,1
p.then(r=>post([r,handler,preIndex]))
//because the promises are stored here you may want to catch it
// you can then resolve with special Fail value and have orderedHandler
// deal with it
.catch(e=>
post(
[
new Fail([e,r,preIndex]),//resolve to Fail value if rejected
handler,
preIndex
]
)
)
})(preIndex,orderedHandler);//closure on index and ordered handler
};
//this will handle promise resolving
const post = resolve=>{
//got another resolved promise
postIndex++;
//store the details (it's resolve value, handler and index)
stored.push(resolve);
//deconstruct the resole value
const [r,handler,i]=resolve;
//the index of the resolve is same as current index
// that means we can start calling the resolvers
if(i===postIndex){
//sort the stored by their indexes (when they stared)
stored = stored
.sort((x,y)=>x[2]-y[2])
//filter out all the ones that can be resolved
.filter(
([r,handler,i])=>{
//can be resolved, no promises have yet to be resolved
// before this index
if(i<=postIndex){
//increase the number of indexes procssed (or stored)
postIndex++;
//resolve the value again (so we don't get errors)
Promise.resolve([r,i]).then(handler);
return false;//no need to "resolve" this again, filter it out
}
return true;
}
)
}
};
pre(promise);
};
})(0,0,[])//passing in pre and post index and stored


//demo on how to use it:
const later = resolveValue => {
const values = ["A","B","C"];
const index = values.indexOf(resolveValue);
return new Promise(
(resolve,reject)=>
setTimeout(
x=>resolve([resolveValue,(4-(index*2))])
,(4-(index*2))*1000
)
)
};
const fastHandler = val => ([resolve,seconds])=>
console.log(
val,
"FAST HANDLER --- resolved with:",
resolve,
"in",seconds,"seconds"
);
const orderedHandler = val => ([[resolve,seconds],i])=>
console.log(
"Call id:",
i,
"ORDRED HANDLER --- resolved with:",
resolve,
"in",seconds,"seconds"
);
const valueArray = ["A","B","C","A","B","C","A"];
console.log("making request:",valueArray);
valueArray
.forEach(
val=>
resolveOrderedAndFast
(fastHandler(val))
(orderedHandler(val))
(later(val))
);

setTimeout(
()=>
console.log("making more requests:",valueArray) ||
valueArray
.forEach(
val=>
resolveOrderedAndFast
(fastHandler(val))
(orderedHandler(val))
(later(val))
)
,500
);

关于javascript - 如何按顺序调用异步 Action 创建者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48081810/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com