РАЗРЕШЕНО: как можно разорвать цикл for на основании ответа от обещания? - PullRequest
1 голос
/ 01 апреля 2019

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

У меня есть цикл for, который будет отправлять запросы к API через выборку.Количество циклов будет основано на переменной.Я хочу иметь возможность обрабатывать ответ от каждой выборки по мере их поступления, и если какой-либо из них когда-либо обнаруживается с результатом true, я хочу, чтобы он не позволял продолжить цикл for.В настоящее время он работает так, что обновляет страницу (что останавливает мой цикл), но это очень неэффективно.Мне просто нужно было как-то это сделать.

Что касается синхронного / асинхронного, я хочу, чтобы он отправлял запросы независимо от ответа, пока ответ не станет истинным, тогда я хочу, чтобы он прекратил отправлять запросы.Ничего страшного, если у меня есть несколько запросов, что происходит сейчас с моим методом обновления страницы.

Я открыт для предложений и для обновления всего этого (я просто изучаю вещи, когда я иду, и даже не знаю, что такое JS 2 месяца назад. Но из всего, что я понял, как это сделать, я не могуКажется, эта концепция понятна.)

Я попытался назвать цикл и разбить @ name, попытался вернуть разрыв, и ничего, что я пробовал, не получилось.Я думаю, единственное, что имеет обновление страницы, это один из способов остановить цикл.

var reqs = 5000;
xId = 970;
xSym = mySymbol;

var looper = async function () {
  for (var start = 1; start < reqs; start++) {
    await new Promise(resolve => { 
        setTimeout(function () { 

            //This is essentially what I need to loop over and over.
            //but not any faster then 200 ms per request. 

            fetch("https://example.com/api/send", {"credentials":"include","body":`{\"xactionId\":\"${xId}\",\"symbol\":\"${xSym}\"}`,"method":"POST","mode":"cors"})
            .then(resp => resp.json())
            .then(json => {
            if(json.test.result === true) { 
                console.log(json.test.hash, json.test.number); 
                    //  
                    //This is where I want to be able to stop the loop
                    //If any of the completed results 
                    //come back true to have it discontinue the Looper
                    //
                    //currently I do a window.location.reload();
                    //  
            }})
            .catch(err => console.log(err));

            resolve(true);
          }, 200);
    });
  }
  return true;
}
looper().then(function(){
  console.log("Got a match!");
});

И на всякий случай, если кому-то понадобятся ответы, которые я получаю с сервера.

{
  "result": {
    "hash": "dbbb42b293",
    "result": false,
    "isHigh": false,
    "number": 4993,
    "threshold": 3,
    "chance": 0.03,
    "nonce": 2194375,
    "created": 1554150935
  },
  "dailyFree": false,
  "status": null,
  "user": {
    "hash": "aabbccdd8f",
    "level": 300,
    "username": "user",
    "requests": 4440936,
    "nonce": 2194376,
    "volume": "11.10794076",
    "lockedBalance": null,
    "session": {
      "requests": 5,
      "volume": "0.000004"
    }
  }
}

Я хочу иметь возможность остановить цикл for в асинхронной функции looper на основе результата во втором .then после запроса POST.

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


РЕШЕНИЕ: Я использовал последний вариант, предложенный @Bergi.Спасибо за помощь!

мой окончательный код выглядит так:

var reqs = 5000;
xId = 970;
xSym = mySymbol;
function delay(t) {
    return new Promise(resolve => setTimeout(resolve, t));
}
async function looper() {
  var run = true;
  for (var start = 1; run && start < reqs; start++) {
    await delay(200);
    fetch("https://example.com/api/send", {"credentials":"include","body":`{\"xactionId\":\"${xId}\",\"symbol\":\"${xSym}\"}`,"method":"POST","mode":"cors"})
    .then(resp => resp.json())
    .then(json => {
      if (json.test.result === true) { 
        console.log(json.test.hash, json.test.number); 
        run = false;
      }
    });
  }
  return true;
}
looper().then(function(){
  console.log("DONE!")
});

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

Избегайте использования 1002 * конструктора antipattern ! Вы должны использовать

function delay(t) {
    return new Promise(resolve => setTimeout(resolve, t));
}

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

async function looper() {
  for (var start = 1; start < reqs; start++) {
    await delay(200);
    const resp = await fetch("https://example.com/api/send", {"credentials":"include","body":`{\"xactionId\":\"${xId}\",\"symbol\":\"${xSym}\"}`,"method":"POST","mode":"cors"});
    const json = await resp.json();
    if (json.test.result === true) { 
      console.log(json.test.hash, json.test.number); 
      break;
//    ^^^^^
    }
  }
  return true;
}

Или, может быть, delay(200) и fetch работают параллельно, так что вы ждете не менее 200 мс, не считая времени, которое требуется для извлечения:

async function looper() {
  for (var start = 1; start < reqs; start++) {
    const [, json] = await Promise.all([
      await delay(200),
      fetch("https://example.com/api/send", {"credentials":"include","body":`{\"xactionId\":\"${xId}\",\"symbol\":\"${xSym}\"}`,"method":"POST","mode":"cors"}).then(resp => resp.json()),
    ]);
    if (json.test.result === true) { 
      console.log(json.test.hash, json.test.number); 
      break;
//    ^^^^^
    }
  }
  return true;
}

Если вы действительно хотели отключить запрос на выборку каждые 200 мс, вы не можете использовать await здесь. Вы должны будете использовать логическую переменную в условии цикла, которая проверяет, хочет ли какой-либо из уже полученных ответов остановить цикл:

async function looper() {
  var run = true;
  for (var start = 1; run && start < reqs; start++) {
//                    ^^^^^^
    await delay(200);
    fetch("https://example.com/api/send", {"credentials":"include","body":`{\"xactionId\":\"${xId}\",\"symbol\":\"${xSym}\"}`,"method":"POST","mode":"cors"})
    .then(resp => resp.json())
    .then(json => {
      if (json.test.result === true) { 
        console.log(json.test.hash, json.test.number); 
        run = false;
//      ^^^^^^^^^^^^
      }
    })
    .catch(err => console.log(err));
  }
  return true;
}
0 голосов
/ 02 апреля 2019

В вашем лупере у вас есть цикл, и вы ожидаете:

var looper = async function () {
  for (var start = 1; start < reqs; start++) {
    await new Promise(resolve => { ... })
  }
}

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

var looper = async function () {
  for (var start = 1; start < reqs; start++) {
    const continue = await new Promise(resolve => {
      setTimeout(function () { 

            //This is essentially what I need to loop over and over.
            //but not any faster then 200 ms per request. 

            fetch("https://example.com/api/send", {"credentials":"include","body":`{\"xactionId\":\"${xId}\",\"symbol\":\"${xSym}\"}`,"method":"POST","mode":"cors"})
            .then(resp => resp.json())
            .then(json => {
            if(json.test.result === true) { 
                console.log(json.test.hash, json.test.number); 
                    resolve(false); //break
            }})
            .catch(err => console.log(err));

            resolve(true); //continue
          }, 200);
    if (!continue) break;
    })
  }
}

По сути, у вас здесь разные контексты, один из которых - цикл, другой - Promise (и обратный вызов setTimeout).Возврат из setTimeout не разрешит ваше обещание и не вернет вам ничего полезного снаружи.То, что мы делаем здесь, это то, что мы ожидаем обещания разрешить и возвращаем логическое значение, которое говорит нам, следует ли нам разорвать цикл.Затем в контексте цикла мы решаем прервать или продолжить.

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