【问题标题】:Using Promises in a loop在循环中使用 Promise
【发布时间】:2021-09-02 12:09:21
【问题描述】:

我尝试创建一个加载测试脚本,但我遇到了奇怪的行为 我使用 https://github.com/prisma-labs/graphql-request 模块进行 graphql 请求。

但我没有看到进程运行到回调中

我看到了下一个结果。它停在前 5 个项目上。

GET:  MX
GET:  MX
GET:  DE
GET:  LT
GET:  US

我想我可能无法访问回调函数中的 requestCount 变量,但我什至看不到请求已发送。

import { request, gql } from 'graphql-request'

const MAX_REQUESTS = 5;
const countries = ['GB', 'UK', 'US', 'LT', 'IT', 'DE', 'MX']
const getRandomElement = (items) => {
    return items[Math.floor(Math.random()*items.length)];
}

let requestCount = 0;
while (true) {
    let country = getRandomElement(countries);
    let query = gql`
{
  country(code: "${country}") {
    name
    native
    capital
    emoji
    currency
    languages {
      code
      name
    }
  }
}`
    if (requestCount >= MAX_REQUESTS) {
        continue;
    }

    console.log('GET: ', country);

    request('https://countries.trevorblades.com/', query).then((data) => {
        console.log('OK: ', country);
        requestCount--;
    }).catch((error) => {
        console.log('FAILED: ', country);
        requestCount--;
        console.error(error)
    })

    requestCount++;
}

【问题讨论】:

  • 你想连续向服务器发出5个请求吗?如果一个请求成功,那么它应该发出另一个请求?
  • 不应该是requestCount++;吗?
  • 网络标签在您的浏览器中显示什么?如果响应超时,它可以堆积请求而不会立即得到响应(然后感觉就像“跳过”了回调,但它只是在等待超时)
  • @Sagar 你说得对

标签: javascript node.js ecmascript-6 request-promise


【解决方案1】:

这是 Node.js 的行为(同步)

如果你有同步的 sn-p 并且里面有异步回调。它将等待同步执行,然后将移动到回调队列。

一个简单的例子

let counter = 0;
while(true) {
    console.log("While", counter++)
    setTimeout(() => {
        console.log("Inside Timeout")
    }, 0)
}

在您的用例中,您可以维护队列或更改条件

【讨论】:

  • 样本中没有“内部超时”文本
  • 正确。这就是我试图说明的行为。因为它不会被执行,因为它仍在运行。
  • 所以我们需要一种方法来停止 while 循环。在您的代码中只需将其更改为 while (requestCount < MAX_REQUESTS)
  • 问题是我需要继续检查池中 5 个项目的大量请求
  • 我会尝试在空闲时间设计队列
【解决方案2】:

您的 while 循环永远不会中断,它会继续执行并占用线程。你的异步函数(Promises)永远没有机会回到线程执行。

编辑:每次发送一个包含 5 个项目的请求。

import { request, gql } from "graphql-request";

const MAX_REQUESTS = 5;
const arr = ["GB", "UK", "US", "LT", "IT", "DE", "MX"];

const getRandomElements = (items, numberOfElements) => {
  return Array.from({ length: numberOfElements }).map(
    _ => items[Math.floor(Math.random() * items.length)]
  );
};

const getQuery = country => gql`
    {
        country(code: "${country}") {
            name
            native
            capital
            emoji
            currency
            languages {
            code
            name
            }
        }
    }`;

(async function run() {
  while (true) {
    const countries = getRandomElements(arr, MAX_REQUESTS);
    const promises = countries.map(country =>
      request("https://countries.trevorblades.com/", getQuery(country))
    );
    const results = await Promises.allSettled(promises);

    results.forEach((res, i) => {
      if (res.status === "fulfilled") {
        console.log(`OK: Country:${countries[i]} data:${res.value}`);
      } else {
        console.log(`FAIL: Country:${countries[i]} Error:${res.reason}`);
      }
    });
  }
})();

【讨论】:

  • 问题是我不需要打破循环我有很多请求需要同时运行 5 个项目来运行
  • @Vlad,好的,我已根据您的更新要求更新了答案。
  • 太好了,如果我做对了,使用回调的函数应该是异步的
  • @Vlad,你提到的回调实际上是承诺。如果你不熟悉 Promise,你会很难理解 async/await 的语法,因为 async/await 是基于 Promise 的。你可能在 js 中看到了 promise 和 async/await。
  • 是的,我查看了有关 async/await 的文档,我只是循环误解了它们
猜你喜欢
  • 2020-07-27
  • 2019-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-08
  • 2016-12-13
  • 1970-01-01
相关资源
最近更新 更多