Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
801 views
in Technique[技术] by (71.8m points)

node.js - How to delay execution of functions, JavaScript

Background

I am trying to create a factory function that executes a specific async function with a given delay.

For the purposes of this question, this will be the async function I refer to:

/*
 *  This is a simulation of an async function. Be imaginative! 
 */
let asyncMock = function(url) {
    return new Promise(fulfil => {

        setTimeout(() => {
            fulfil({
                url,
                data: "banana"
            });
        }, 10000);

    });
};

This function takes an url and it returns a JSON object containing that URL and some data.

All around my code, I have this function called in the following way:

asyncMock('http://www.bananas.pt')
.then(console.log);

asyncMock('http://www.berries.com')
.then(console.log);

//... badjillion more calls

asyncMock('http://www.oranges.es')
.then(console.log);

Problem

The problem here is that all these calls are made at exactly the same time, thus overloading the resources that asyncMoc is using.

Objective

To avoid the previous problem, I wish to delay the execution of all calls to asyncMoc by Xms.

Here is a graphic with what I pretend:

delayed_requests

To achieve this I wrote the following approaches:

  1. Using Promises
  2. Using setInterval

Using Promises

let asyncMock = function(url) {
  return new Promise(fulfil => {

    setTimeout(() => {
      fulfil({
        url,
        data: "banana"
      });
    }, 10000);

  });
};

let delayFactory = function(args) {

  let {
    delayMs
  } = args;

  let promise = Promise.resolve();

  let delayAsync = function(url) {
    return promise = promise.then(() => {

      return new Promise(fulfil => {
        setTimeout(() => {
          console.log(`made request to ${url}`);
          fulfil(asyncMock(url));
        }, delayMs);
      });
    });
  };

  return Object.freeze({
    delayAsync
  });
};

/*
 *  All calls to any of its functions will have a separation of X ms, and will
 *  all be executed in the order they were called. 
 */
let delayer = delayFactory({
  delayMs: 500
});

console.log('running');

delayer.delayAsync('http://www.bananas.pt')
  .then(console.log)
  .catch(console.error);

delayer.delayAsync('http://www.fruits.es')
  .then(console.log)
  .catch(console.error);

delayer.delayAsync('http://www.veggies.com')
  .then(console.log)
  .catch(console.error);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Okay, so here's my solution to your problem. Sorry I had to rewrite your code to better be able to understand it. I hope you can interpret it anyway and get something out of it.

Calls 500ms between eachother using Promises (JSFiddle):

function asyncFunc(url) {
    return new Promise(resolve => {
    setTimeout(function() {
        resolve({ url: url, data: 'banana' });
    }, 2000);
  });
}

function delayFactory(delayMs) {
  var delayMs = delayMs;
  var queuedCalls = [];
  var executing = false;

  this.queueCall = function(url) {
    var promise = new Promise(function(resolve) {
        queuedCalls.push({ url: url, resolve: resolve });
        executeCalls();
    });
    return promise;
  }

  var executeCalls = function() {
    if(!executing) {
      executing = true;
      function execute(call) {
        asyncFunc(call.url).then(function(result) {
            call.resolve(result);
        });
        setTimeout(function() {
            queuedCalls.splice(queuedCalls.indexOf(call), 1);
          if(queuedCalls.length > 0) {
            execute(queuedCalls[0]);
          } else {
            executing = false;
          }
        }, delayMs)
      }
      if(queuedCalls.length > 0) {
        execute(queuedCalls[0]);
      }
    }
  }
}

var factory = new delayFactory(500);
factory.queueCall('http://test1').then(console.log); //2 sec log {url: "http://test1", data: "banana"}
factory.queueCall('http://test2').then(console.log); //2.5 sec log {url: "http://test2", data: "banana"}
factory.queueCall('http://test3').then(console.log); //3 sec log {url: "http://test3", data: "banana"}
factory.queueCall('http://test4').then(console.log); //3.5 sec log {url: "http://test4", data: "banana"}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...