我有一个网页,其中的不同部分都需要相同的后端数据.每个都是孤立的,因此它们最终都会对后端进行相同的调用.
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.
当调用已经在进行中并由同一网页上的不同代码段启动时,避免调用 Web 服务器的最佳方法是什么?
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?
这是一个例子.我将使用 setTimeout 来模拟异步调用.
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.
转储联系人列表:
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);
});
上述例程使用全局 log() 函数.可以使用 console.log() 代替.上面的 log() 函数记录到浏览器窗口,实现如下:
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/>";
}
并且在 html 中需要以下内容:
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.
和
New data received from back-end.
三遍,没必要.
如何解决这个问题?
此示例在 Plunker 上可以执行:http://plnkr.co/edit/6ysbNTf1lSf5b7L3sJxQ?p=preview
This sample is on Plunker can be executed: http://plnkr.co/edit/6ysbNTf1lSf5b7L3sJxQ?p=preview
只需在调用的函数中缓存结果即可:
Just cache the result in the function making the call:
function cache(promiseReturningFn){
var cachedVal = null; // start without cached value
function cached(){
if(cachedVal) return cachedVal; // prefer cached result
cachedVal = promiseReturningFn.apply(this, arguments); // delegate
return cachedVal; // after we saved it, return it
}
cached.flush = function(){ cachedVal = undefined; };
return cached;
}
这有一个警告,即对于 null 的实际结果会失败,否则它可以很好地完成工作.
This has the caveat of failing for actual results that are null but otherwise it gets the job done nicely.
您现在可以缓存任何 promise 返回函数 - 上面的版本只缓存忽略参数 - 但您可以构造一个类似的函数,它具有 Map 并基于不同的参数进行缓存 - 但让我们专注于您的用例.
You can now cache any promise returning function - the version above only caches ignoring arguments - but you can construct a similar one that has a Map and caches based on different arguments too - but let's focus on your use case.
var getContactsCached = cache(getContacts);
getContactsCached();
getContactsCached();
getContactsCached(); // only one async call ever made
cache 方法实际上甚至与 Promise 无关——它所做的只是获取一个函数并缓存它的结果——你可以将它用于任何事情.事实上,如果你正在使用像 underscore 这样的库,你可以使用 _.memoize
来为你做这件事.
The cache method is actually not even related to promises - all it does is take a function and cache its result - you can use it for anything. In fact if you're using a library like underscore you can use _.memoize
to do it for you already.
这篇关于如何处理对后端服务进行相同调用的多个浏览器脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!