解决:如何根据promise的响应打破for循环?

问题描述 投票:0回答:2

所以我正在编写一个脚本,在网站上自动为我执行一些操作。到目前为止,我已经想到了所有的东西,但我正在做一些不正确的事情,只是想找出一个更好的方法来做到这一点。

我有一个for循环,它将通过fetch向API发送请求。循环次数将基于变量。我希望能够处理来自每个fetch的响应,如果它们中的任何一个显示出结果为true,我希望它阻止我的for循环继续。目前我的工作方式是它将刷新页面(这将停止我的循环),但这是非常低效的。我只是需要以某种方式完成它。

至于同步/异步我希望它发送请求而不管响应,直到响应为真,然后我希望它停止发送请求。如果我有一些请求,那么现在我的页面刷新方法会发生什么,这是没关系的。

我愿意接受建议并改进整个事情(我只是学习我去的东西,甚至不知道2个月前的js。但是对于我已经弄清楚如何做的所有事情,我似乎无法掌握这个概念。 )

我已经尝试命名循环并破坏@ 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"
    }
  }
}

我希望能够在获取POST请求之后根据第二个.then中的结果在looper异步函数中停止for循环。

另外,我想知道上述是否可能同时在其自己的外部函数中具有获取请求,以便我也可以从代码中的其他位置调用它。


解决方案:我使用了@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!")
});
javascript loops fetch-api
2个回答
1
投票

避免Promise constructor antipattern!你应该用

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

而不是在其他地方使用Promise构造函数,尤其是包装其他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并行运行,这样你就可以在至少200ms的时间内等待获取时间:

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;
}

如果你真的wanted to fire off每200ms获取一次请求,你不能在这里使用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;
}

-1
投票

你的循环器中你有循环,你做了等待:

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

Await可用于将您的承诺结果分配给变量。这样你就可以在承诺之外控制你的循环。

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返回不会解决您的承诺,也不会返回任何有用的东西。我们在这里做的是等待承诺解决,我们恢复一个布尔值,告诉我们是否应该打破循环。然后,在循环的上下文中,我们决定中断或继续。

© www.soinside.com 2019 - 2024. All rights reserved.