Избегайте параллельного выполнения тела функции по пользовательским событиям, пока не завершится ранее запущенное выполнение - Javascript - PullRequest
2 голосов
/ 02 апреля 2020

В моей реализации компонента функция doSomething запускается нажатием кнопки пользователя. Проблема в том, что doSomething занимает около 200-1100 мсек для завершения выполнения с изменением состояния. Я сталкиваюсь с проблемой, когда быстрое нажатие кнопки одновременно вызывает это тело функции, что вызывает неожиданные конечные состояния.

I не требует сложного решения взаимного исключения . Требование состоит в том, чтобы просто игнорировать все другие вызовы, пока текущее выполнение не завершится, я попробовал следующий подход пометки:

doSomething = () => {
    if(this.running){
        return //ignore the event
    }
    this.running=true;
    //do processing
    this.setState({someVariable:answer_of_process}, ()=>this.running=false);
}

render(){
    return(<ImportedComponent doSomething={this.doSomething}/>)
}

Это уменьшило вероятность повреждения состояния, но иногда это происходит. ie: до 20%, сейчас 2% . Как улучшить это решение, чтобы оно составляло 0% от частоты отказов?

Отредактировано: Кнопка запуска функции создана из импортированного сложного компонента и не может быть отключена. Компонент принимает doSomething в качестве реквизита.

Ответы [ 2 ]

2 голосов
/ 02 апреля 2020

Предполагается, что вам нужно только последнее действие, выполненное в течение определенного периода времени после запуска нескольких событий.

Это относится к полю debounce function.

Создает отклоненную функцию, которая задерживает вызов функции до истечения миллисекунд ожидания с момента последнего вызова отклоненной функции.


Например: если пользователь вводит очень быстро, и запрос стоит раз, мы хотим, чтобы было запущено только последнее введенное пользователем значение.

import React, { useState, useCallback } from "react";
import "./styles.css";
import { debounce } from "lodash";

const request = debounce(value => {
  alert(`request: ${value}`);
}, 1000);

export default function App() {
  // const [input, setInput] = useState("");
  const debouceRequest = useCallback(value => request(value), []);
  const onChange = e => {
    // setInput(e.target.value);
    debouceRequest(e.target.value);
  };
  return (
    <div className="App">
      <input onChange={onChange} />
      {/* {input} */}
    </div>
  );
}

Edit elated-dawn-lb5ex

1 голос
/ 02 апреля 2020

Если у кого-то есть проблема, я адаптировал решение из отмеченного ответа для этого вопроса с минимальными правками:

const _ = require('lodash');

doSomething = _.debounce(() => {
    if(this.running){
        return //ignore the event
    }
    this.running=true;
    //do processing
    this.setState({someVariable:answer_of_process}, ()=>this.running=false);
}, 500)

render(){
    return(<ImportedComponent doSomething={this.doSomething}/>)
}
...