A feladat
ASP.NET-ben kell azt megoldanom, hogy ha a felhasználó egy képen (szerveroldalon generált térkép) lekattint pontokat, akkor rajzoljak a lekattintott pontokat összekötő törtvonalat, és az egész "ne villogjon" (AJAX).
A feladat elsőre egyszerűnek hangzik:
- javascriptben elkapom a kattintást
- aszinkron meghívok egy szerveroldali metódust (például PageMethod), ami elvégzi a rajzolást a szerver memóriájában lévő térképre
- az aszinkron hívás eredményekor javascriptből újratöltöm a térképet, hogy a szerveroldalon kész rajzolás látszódjon a böngészőben is
Megírtam, kipróbáltam, jónak tűnt. Kattintottál a térképen, kicsit nézted, és már láttad is, ahogy nő a törtvonal...
A probléma
Aztán jött egy rutinos kattintgató, aki nem várta meg, hogy kattintásának eredménye megjelenjen, hanem gyorsan lekattintott néhány tíz pontot egy körvonal mentén, és várta, hogy megjelenjen a kör. És itt jött a meglepetés: nem a lekattintott körvonal jelent meg, hanem egy összevissza vonal. Látszott, hogy a megjelent kriksz-kraksz a kattintott pontokat köti össze, tehát a gond a pontok összekötési sorrendje volt.
Ötletek
Először azt hittem, hogy biztos a GDI-os DrawPolygon methódus a ludas, és nem jó sorrendbe köti össze a jó sorrendbe kattintott pontokat. Végül rájöttem, hogy a gyors kattintgatásnak aza az eredménye, hogy az általuk kiváltott sok aszinkron kérés elkezd versenyezni a szerveren, és egyáltalán nem biztos, hogy ugyanabban a sorrendben futnak le a kritikus szerveroldali részeik, mint amilyen sorrendben a kéréseket a böngészőből útjukra indítottuk. (Tegye fel a kezét, aki nem gondolt még arra, hogy a Framework bugos, nem pedig amit ő írt.)
Ellenőrzés
Az elképzelés ellenőrzésére, készítettem egy egyszerű weblapot, amin van:
- egy gomb
- egy számláló
- egy szövegmegjelenítő div
Ha megnyomod a gombot, megnöveli a számlálót, a pillanatnyi értékét átdobja szerveroldalra (PageMethod hívással), ahol ezek az értékek szövegként egymás mögé íródnak (lista készül belőlük), majd ez az eredmény-szöveg visszakerül javascript-oldalra, ahol beíródik az eredmény megjelenítő div-be.
Az elvárt működés a következő: nyomkodom a gombot és alatta egy számsort (ez az eredmény-szöveg) látok nőni: 0 1 2 3 4 5 6 ...
A valós működés viszont: kellően gyors kattintgatás esetén a számok néha nem sorrendben vannak, azaz más a szerveroldali metódusok lefutási sorrendje, mint az őket kiváltó kliensoldaliaké.
Jó, így utólag már nekem is nyilván...
A kellően gyors kattingatást egy for ciklus tudja egyébként.
A tesztalkalmazás
Markup:
<form id="mainForm" runat="server">
<input type="button" value="N?vel ?s megjelen?t" onclick="buttonClick()" />
<asp:ScriptManager ID="scriptManager" runat="server" EnablePageMethods="true" />
<div id="divResult" />
</form>
<script language="javascript" type="text/javascript">
counter = 0
function buttonClick() {
for( i = 0; i < 100; i++ ) {
PageMethods.TestMethod( counter, testMethodCompleted )
counter++
}
}
function testMethodCompleted( result ) {
$get( 'divResult' ).innerText = result
}
</script>
CS:
public partial class _Default : System.Web.UI.Page
{
private static StringBuilder sb = new StringBuilder();
[ WebMethod ]
public static string TestMethod( string data )
{
sb.Append( data );
sb.Append( " " );
return sb.ToString();
}
}
És a kattintgatások eredménye:
