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
273 views
in Technique[技术] by (71.8m points)

javascript - How do I handle multiple browser scripts making the same calls to the back-end service

I have a web page where different parts of it all need the same back-end data. Each is isolated, so they each end up eventually making the same calls to the back-end.

What is the best way to avoid making a call to the web server when one is already in progress and initiated by a different piece of code on the same web page?

Here's an example. I'll use setTimeout to simulate an asynchronous call.

Let's assume there's an async function that returns the list of contacts, which is basically a simple array of strings in this example:

var getContacts = function() {
  log('Calling back-end to get contact list.');
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      log('New data received from back-end.');
      resolve(["Mary","Frank","Klaus"]);
    }, 3000);
  });
};

Now, let's create three separate functions that each call the above function for different purposes.

Dump out the list of contacts:

var dumpContacts = function() {
  getContacts().then(function(contacts) {
    for( var i = 0; i < contacts.length; i++ ) {
      log( "Contact " + (i + 1) + ": " + contacts[i] );
    }
  });
};

Determine if a particular contact is in the list:

var contactExists = function(contactName) {
  return getContacts().then(function(contacts) {
    return contacts.indexOf(contactName) >= 0 ? true : false;
  });
};

Get the name of the first contact:

var getFirstContact = function() {
  return getContacts().then(function(contacts) {
    if ( contacts.length > 0 ) {
      return contacts[0];
    }
  });
};

And here is some example code to use these three functions:

// Show all contacts
dumpContacts();

// Does contact 'Jane' exist?
contactExists("Jane").then(function(exists){
  log("Contact 'Jane' exist: " + exists);
});

getFirstContact().then(function(firstContact){
  log("first contact: " + firstContact);
});

The above routines make use of a global log() function. console.log() could be used instead. The above log() function log's to the browser window and is implemented as follows:

function log() {
  var args = Array.prototype.slice.call(arguments).join(", ");
  console.log(args);
  var output = document.getElementById('output');
  output.innerHTML += args + "<br/>";
}

and requires the following in the html:

<div id='output'><br/></div>

When the above code is run, you will see:

Calling back-end to get contact list.

and

New data received from back-end.

three times, which is unnecessary.

How can this be fixed?

This sample is on Plunker can be executed: http://plnkr.co/edit/6ysbNTf1lSf5b7L3sJxQ?p=preview

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

If the desire is to reduce the number of unnecessary calls to the back-end, then hang on to the promise and while it's still unresolved, return it it for new calls rather than issuing another call to the back-end.

Here's a routine that converts an async function, one that returns a promise, into one that's only called while the promise is still unresolved.

var makeThrottleFunction = function (asyncFunction) {
  var currentPromiser = getPromise = function() {
    var promise = new Promise(function(resolve, reject) {
      asyncFunction().then(function(value) {
        resolve(value);
        currentPromiser = getPromise;
      }).catch(function(e) {
        reject(e);
        currentPromiser = getPromise;
      });
    });

    currentPromiser = function() {
      return promise;
    };

    return promise;
  }

  return function () {
    return currentPromiser();
  };
};

In your routine, you can convert getContacts like so:

var getContacts = makeThrottleFunction(getContacts);

Or pass the entire body of the function directly.

Keep in mind that this will only work for parameterless calls to the back-end.

Example plunker code: http://plnkr.co/edit/4JTtHmFTZmiHugWNnlo9?p=preview


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

...