Как я могу одновременно запустить 3 экземпляра функции - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть функция с именем scan(). Он вызывается в al oop. Однако, как это работает в данный момент:

  1. Звонки scan()
  2. Ожидание возврата scan()
  3. Увеличение min
  4. Повтор

Как мне сделать так, чтобы он одновременно запускал 2 экземпляров scan(). Где я могу изменить 2 экземпляров на 3 экземпляров или 4 или 5 et c.

Пример: Как я хочу, чтобы это было (ниже пример: 3 экземпляров scan(), запущенных в любой момент времени. Никогда не должно быть больше, чем 3 экземпляров запущенного сканирования (относительно условия while l oop).

Вызывает scan() и ожидает возврата значения в фоновом режиме. Как только он получает возвращаемое значение, он увеличивает min и вызывает другой экземпляр scan(). Всегда есть 3 экземпляров scan(), работающих (относительно время l oop состояние)

<script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<div class="display-error" style="display: none"></div>
<form>
  <label for="fname">Fruit (only correct input is: banana)</label><br>
  <input type="text" id="fruit-name" name="fruit" value="banana"><br>
  <button type="submit" id="submit" value="Submit">Submit</button>
</form>

<div id="results">
</div>

<script type="text/javascript">
$(document).ready(function() {


    $('#submit').click(function(e) {
        e.preventDefault();

        var fruitName = $("#fruit-name").val();

        $.ajax({
            type: "POST",
            url: "verify-input.php",
            dataType: "json",
            data: {
                fruitName: fruitName
            },
            success: function(data) {
                if (data.code == 200) {
                    $("#submit").html("Running Scan");
                    (async function() {
                        var fruitID = data.fruitId;
                        var min = 1;
                        while (min < 1000) {
                            await scan(fruitID, min, min + 30);
                            min = min + 30;
                        }
                    })();
                } else {
                    $(".display-error").html("<ul>" + data.msg + "</ul>");
                    $(".display-error").css("display", "block");
                }
            }
        });


    });
});

function scan(vFruitId, min, max) {

    return $.ajax({
        type: "POST",
        url: "scanner.php",
        dataType: "json",
        data: {
            vFruitId: vFruitId,
            min: min,
            max: max
        },
        success: function(data) {
            data.forEach((item, idx) => {
                $("#results").append(`
                <div class="fruit-item" data-item="${idx}">
                    <div class="f-calories">calories: ${item.sweetness}</div>
                    <div class="f-sweetness">sweeteness: ${item.calories}</div>
                    <div class="f-bitterness">bitterness: ${item.bitterness}</div>
                </div><br>
              `);
            })
        }
    });

}

</script>

Ответы [ 2 ]

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

Это код, который вы хотите запускать одновременно.

//...
while (min < 1000) {
  await scan(fruitID, min, min + 30);
  min = min + 30;
}
//...

В данный момент он работает синхронно.

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

Реализация будет выглядеть примерно так:

const promiseThrottle = new PromiseThrottle({
    requestsPerSecond: 5, // up to 5 requests per second.. This will adjust the request rate
    promiseImplementation: Promise, // the Promise library you are using
});

const scans = [];
// swapped while loop with for loop but it accomplishes effectively the same task
for (let i = 0; i < 1000; i += 30) {
    // closure in order to get correct value of i on each iteration.
    ((min) => {
        scans.push(promiseThrottle.add(() => scan(fruitId, min, min + 30)));
    })(i);
}

Promise.all(scans).then(res => {
    // res is an array of all responses from scans
    // scans completed
});

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

0 голосов
/ 24 апреля 2020

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

function throttle(max, fn) {
  let queue = [];
  let inProgress = new Set();

  const runTaskNow = async (args) => {
    inProgress.add(args);
    await fn(...args);
    inProgress.delete(args);

    const next = queue.shift();
    if (next) {
      runTaskNow(next.args).then(next.resolve, next.reject);
    }
  };

  const runTaskLater = args => {
    let resolve, reject;
    const promise = new Promise((yes, no) => {
      resolve = yes;
      reject = no;
    });
    queue.push({ resolve, reject, args });
    return promise;
  };

  return (...args) => {
    return inProgress.size < max ? runTaskNow(args) : runTaskLater(args);
  }
}

Чтобы использовать, оберните вашу функцию с помощью throttle:

const scan = throttle(5, (vFruitId, min, max) => {
  return $.ajax({
    // ...
  });
});

... затем назовите это так, как вы обычно звоните scan.

...