Один из подходов состоит в том, чтобы post
подключиться к обещанию, а не работать непосредственно с объектом состояния. Это обещание может быть сохранено в самом объекте состояния. Он начинается с государственного объекта. post
обновляет его следующим образом:
const post = (n, state) => {
return state.promise = state.promise
.then(state => {
// ...do stuff here that updates (or replaces) `state`...
return state;
}));
};
Вот пример (в JavaScript, но вы можете добавить аннотации типов), используя asyncAction
(это как ваш promiseTimeout
, но без он возвращает функцию, которую мы вызываем немедленно, не
"use strict";
let localState = {
state: 1000
};
localState.promise = Promise.resolve(localState);
// I'm not sure why this *returns* a function that we
// have to call, but...
const promiseTimeout = (time, value) => () => new Promise((resolve) => setTimeout(resolve, time, value + time));
const post = (n, state) => {
return state.promise = state.promise
.then(state => promiseTimeout(n, state.state)().then(newValue => {
state.state = newValue;
console.log(state.state);
return state;
}));
};
console.log("Running...");
post(1000, localState); // localState at call time is 1000
post(3000, localState); // localState at call time is still 1000
Поскольку каждый вызов post
синхронно заменяет обещание новым обещанием, цепочка строится из вызовов post
.
Вот что в TypeScript (с небольшим количеством взлома в одном месте, вы, вероятно, можете улучшить это); ссылка на игровую площадку .
type State = {
state: number,
promise: Promise<State>
};
let localState: State = (() => {
const s: Partial<State> = {
state: 1000
};
// There's probably a better way to handle this than type assertions, but...
s.promise = Promise.resolve(s as State);
return s as State;
})();
// I'm not sure why this *returns* a function that we
// have to call, but...
const promiseTimeout = (time: number, value: number) => () => new Promise(
(resolve: (n: number) => void) => setTimeout(resolve, time, value + time)
);
const post = (n: number, state: State): Promise<State> => {
return state.promise = state.promise
.then(state => promiseTimeout(n, state.state)().then(newValue => {
state.state = newValue;
console.log(state.state);
return state;
}));
};
console.log("Running...");
post(1000, localState); // localState at call time is 1000
post(3000, localState); // localState at call time is still 1000
Стоит отметить, что в подобных ситуациях, когда состояние может изменяться асинхронно, как это, часто стоит создать new объект состояния при его изменении, а не изменении существующего - например, обрабатывать аспекты состояния как неизменные.