дроссель выполняет функцию не более одного раза за период ожидания, верно? - PullRequest
0 голосов
/ 14 мая 2019

Я хочу регулировать свою функцию каждые 100 миллисекунд. В следующем коде я ожидаю, что будут напечатаны только 1 и 3. Но 2 также печатается в фактическом результате.

function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100);

setTimeout(() => {
  t(1);
}, 50);
setTimeout(() => {
  t(1);
}, 50);
setTimeout(() => {
  t(1);
}, 50);
setTimeout(() => {
  t(1);
}, 55);
setTimeout(() => {
  t(2);
}, 55);
setTimeout(() => {
  t(3);
}, 500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.1/lodash.js"></script>

Мне нужно изменить время ожидания газа на 500, чтобы отфильтровать 2.

Может быть, мое понимание дроссельной заслонки неверно. Разве дроссель не должен выполнять функцию не более одного раза за период ожидания?

Ответы [ 3 ]

4 голосов
/ 14 мая 2019

Ваше понимание того, как вы используете эту настройку дроссельной заслонки, не совсем верно.

Прямой ответ:

Не следует дроссельной заслонке выполнять функцию не более одного раза за ожиданиеperiod?

Если параметры не переданы, throttle будет выполняться в начале и в конце периода ожидания (дважды) при условии, что функция throttled была вызвана более одного раза за этот период.

Через 50 мс вызывается ваша первая функция, и «дроссель» запускает ее немедленно, также в это время ваш следующий f (1) ставится в очередь для вызова через 100 мс.Но затем вызывается другой f (1), другой f (1) и затем f (2), и каждый новый заменяет последний как функцию, вызываемую при 100 мс (это время, которое вы прошли в газ).Затем проходит более 100 мс, а затем вызывается более или менее f (3), когда это должно быть.

Если вы не передадите какие-либо параметры в _.throttle, он немедленно вызовет первый запуск функции (при 0 мс)и затем вызовет последнюю функцию, запущенную в течение установленного периода времени, по истечении этого времени.

Использование кода @ zfrisch в качестве начала:

function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100);
const TO = (n, i) => setTimeout(() => {
  t(n);
}, i);

TO(1, 50); // logged immediately
TO(1, 50);
TO(1, 50);
TO(1, 55);
TO(2, 55); // logged at 100ms (as it was the last function attempted)
function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100, { leading: false });
const TO = (n, i) => setTimeout(() => {
  t(n);
}, i);

TO(1, 50); // not logged at all
TO(1, 50);
TO(1, 50);
TO(1, 55);
TO(2, 55); // logged at 100ms (as it was the last function attempted)
function say(what) {
  console.log(what);
}

const t = _.throttle(say, 100, { trailing: false });
const TO = (n, i) => setTimeout(() => {
  t(n);
}, i);

TO(1, 50); // logged immediately
TO(1, 50);
TO(1, 50);
TO(1, 55);
TO(2, 55); // not logged at all
3 голосов
/ 14 мая 2019

Дроссель задержит выполнение на время ожидания, но функция все равно будет вызываться. В вашем примере это произойдет следующим образом: через 50 мс после запуска скрипта будет зарегистрирована первая 1, и в этот момент газ начнет отсчитывать 100 мс. Любой вызов t в этот период будет отложен. После того, как пройденные 100 мсек, будет выполнен последний вызов t. 100 мс проходит снова и t не вызывается, поэтому ничего не происходит, затем происходит последний вызов.

1 голос
/ 14 мая 2019

Проблема:

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

Функция Throttle:

Throttle Parameters

Из приведенного выше вы можете видеть, что Throttle принимает function и wait время в миллисекундах в качестве своих первых двух параметров, но options не используется в вашем текущем коде, и они являются ключом к решение вашей проблемы.


Опции:

_.throttle имеет опции leading и trailing. Эти два значения по умолчанию true.

К сожалению, названные опции, хотя и подходящие, не являются кристально понятными по назначению просто из их имен, если вы не знакомы с процессом, который происходит за занавесом.


Объяснение:

leading относится к тем, которые вызываются в соответствующее время. Это будет:

  • начальный звонок
  • следующий звонок после 100мс
  • следующий звонок после еще 100 мс
  • и т.д.

trailing относится к последнему вызову функции throttle, выполненной в течение интервала. Эта функция не просто удаляется, а откладывается до тех пор, пока не будет вызвана . Думайте об этом как о слоте, который доступен для заполнения в течение интервала. Когда во время интервала выполняется вызов, этот слот заполняется / заменяется новой функцией.

Это можно проиллюстрировать:

  • Первый звонок сделан
  • В течение интервала
  • В течение интервала
  • function 2 заменяет function 1 в качестве конечной функции
  • При 100ms function 2 выполняется.

Важной концепцией и, в конечном счете, сутью того, что происходит в вашем коде, является следующее:

Если обе опции true, функция трейлинг сделана в течение , интервал будет вызываться до нового ведущего вызова к функции throttle.

Из-за этого новый ведущий вызов становится завершающим вызовом для окончания следующего интервала.

Документация, которую я получил непосредственно с официального сайта lodash, действительно указывает на это, но вы были бы прощены за недопонимание, так как это многое понять, если вы не знакомы с их условиями:


Throttle Documentation * См. Документацию по дроссельной заслонке на Lodash


Что это значит?

В вашем примере, когда вы вызываете _.throttle, по умолчанию будет ждать выполнения вызова функции, пока не пройдет интервал, и непрерывно переписывать функцию, ожидающую вызова в течение 100ms интервал. Чтобы изменить это и принимать / выполнять только те звонки, которые сделаны после интервала, вы можете включить trailing в false.

Рабочий раствор:

function say(what) {
console.group();
  console.log(what);
  console.timeLog("check");
  console.groupEnd();
}

const t = _.throttle(say, 100, {trailing: false});
const TO = (n, i) => setTimeout(()=>{t(n);}, i);
 
console.time("check");
TO(1,50);
TO(1,50);
TO(1,50);
TO(1,55);
TO(2,55);
TO(3,500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
...