【问题标题】:Node.js - Working with an API limit of 5 requests per secondNode.js - 使用每秒 5 个请求的 API 限制
【发布时间】:2018-03-23 21:29:34
【问题描述】:

我有一个“脚本”,可以对特定 API 执行数千个请求。这个 API 每秒只允许 5 个请求(可能它的测量方式与我不同)。为了提出请求,我使用了request-promise 框架,并且我已经用这个取代了普通的request-promise 函数:

const request_promise  = require('request-promise')

function waitRetryPromise() {
  var count = 0 // keeps count of requests
  function rp(options) {
    const timedCall = (resolve) => setTimeout( ()=>resolve(rp(options)),1000) // recursive call
    count += 1
    if (count % 3 == 0) { // recalls after a second on every third request
      return new Promise(timedCall)
    } else {
      return request_promise(options)
    }
  }
  return rp
}

const rp = waitRetryPromise()

一旦连续发出大约 300 个请求(给予或接受),这些请求就会开始相互干扰。有没有人有更好的解决方案?我认为对同一函数的递归调用会有所帮助,它确实有效,但并没有解决问题。也许有一种模式来排队请求,一次做几个?也许是图书馆?

谢谢!

【问题讨论】:

  • these requests start to interfere with each other以什么方式?
  • 还是想知道these requests start to interfere with each other是什么意思
  • 所以,没有回答有效问题?
  • 抱歉,我在睡前问了这个问题。我上面引用的意思是,只要有足够的请求,当我做出一些延迟时,一些不可避免的仍然会与一些后来的非延迟的同时开始,从而导致同样的问题。 :-)
  • 所有答案似乎都应用了近似延迟以达到预期的结果。我喜欢将每次调用次数限制为 API 限制的想法,并且会继续这样做。

标签: javascript node.js promise request-promise


【解决方案1】:

好的,与其重复调用 rp 等,只需确保您在请求之间延迟适当的量......每秒 5 次,即 200 毫秒

function waitRetryPromise() {
    let promise = Promise.resolve();
    return function rp(options) {
        return promise = promise
        .then(() => new Promise(resolve => setTimeout(resolve, 200)))
        .then(() => request_promise(options));
    }
}
const rp = waitRetryPromise();

【讨论】:

  • 尽管我会尝试,但我认为这不会产生预期的效果。由于许多人同时排队,所以他们不会都有延迟然后在同一时间开始吗?
  • 是的。出于某种原因,我一直在弄乱你的代码。应该看到我的第一次尝试!所以很糟糕
  • return promise.then.... 更改为 return promise = promise.then.... 以使其正常工作
【解决方案2】:

我的代码将运行TimedQueue,只要他们有工作要做。 process() 方法在所有工作完成后解析:

class Queue {
    constructor() {
        this.queue = [];
    }

    enqueue(obj) {
        return this.queue.push(obj);
    }

    dequeue() {
        return this.queue.shift();
    }

    hasWork() {
        return (this.queue.length > 0);
    }
}

function t_o(delay) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve();
        }, delay);
    });
}

class TimedQueue extends Queue {
    constructor(delay) {
        super();
        this.delay = delay;
    }

    dequeue() {
        return t_o(this.delay).then(() => {
            return super.dequeue();
        });
    }
    
    process(cb) {
        return this.dequeue().then(data => {
            cb(data);
            if (this.hasWork())
                return this.process(cb);
        });
    }
}


var q = new TimedQueue(500);

for (var request = 0; request < 10; ++request)
    q.enqueue(request);

q.process(console.log).then(function () {
    console.log('done');
});

【讨论】:

  • 在您的情况下,将TimedQueue 的延迟更改为200 (1/5) 秒。
  • 还没有详细阅读代码(我喜欢这个比我在某些方面要发布的内容更好),但是如果在q.process 之后调用q.enqueue 它还能工作吗?如果q.enqueueconsole.log('done'); 之后被调用,你必须再次q.process 吗?
  • 抱歉,是的,您可以在队列处理过程中添加工作,它将继续运行,最终处理新入队的项目,无需再次调用 process。
  • 不,你说得很有道理,我应该自己做测试——一旦队列为空,添加到它意味着你需要再次处理(看,我测试了它:p)
  • @Raf 我喜欢这个解决方案,但我更喜欢另一个,它需要更少的理解/复杂性。但是,请把它留在这里 - 它很棒,可能正是某些人想要的。
【解决方案3】:

我不确定,但也许你从下面得到一些想法

function placeAnOrder(orderNumber) {
    console.log("customer order:", orderNumber)
    cookAndDeliverFood(function () {
        console.log("food delivered order:", orderNumber);
    });
}

//  1 sec need to cook

function cookAndDeliverFood(callback){
    setTimeout(callback, 1000);
}

//users web request
placeAnOrder(1);
placeAnOrder(2);
placeAnOrder(3);
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 嘿 Raj,感谢您的发布,但您的代码在某些方面是我已经拥有的代码的内部。它不会解决问题,因为您所做的只是让每个请求花费 1 秒,但所有请求(如果异步产生)仍将在同一秒内发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-13
  • 2012-02-02
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多