問題描述
我有一個網頁,其中的不同部分都需要相同的后端數據.每個都是孤立的,因此它們最終都會對后端進行相同的調用.
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.
這篇關于如何處理對后端服務進行相同調用的多個瀏覽器腳本的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!