Пускане на асинхронни ajax рекуести към масив от url-и и обработването им наведнъж

Днес имах много интересен случай, в който трябваше да вземем няколко SVG файлове с ajax и после да ги обработим наведнъж когато всички рекуести са готови.

Знам за $.when но съм го използвал само когато броя на рекуестите са фиксиран брой.

Нещо като това тук:

$.when( $.ajax( 'first.svg' ), $.ajax( 'second.svg' ) ).done( function( ajax1, ajax2 ) {
    // do stuff with both things.. as ajax1[0] is the svg document
    // for the first.svg and ajax2[0] is the svg document for the 
    // second.svg
});

Ясно е, че ще ползваме нещо сходно и за това слагаме всеки от ajax извикванията в масив, че да можем да ги добавяме динамично.

// svgUrlArray is an existing array with all the urls of the svgs

// we create a new array with all the ajax calls
var svgAjaxArray = [];

for( var svgIndex = 0; svgIndex < svgUrlArray.length; svgIndex++ ) {
    svgAjaxArray.push( $.ajax( svgUrlArray[ svgIndex ] ) );
}

След това подаваме масива на $.when

$.when( svgAjaxArray ).done( function() {
    // this is executed a bit too early 
});

И хендлъра на done събитието е извикан прекалено рано. Защо?

Защото Array не е Deffered обект – той е просто масив и стойността му е готова за използване веднага (точно като Deffered обект, който се resolve-а веднага при създаването си). И за това done callback-а се извиква веднага.

И какво ни е най-лесното решение тогава?

$.when.apply( $, svgAjaxArray ).done( function() {
    // Now we're talking ;)
    // You must use the arguments variable to get all the entries
    // because you don't know what is the length of the ajaxArray
});

Вече може да обработваме произволен брой от асинхронни заявки и да ги обработваме след като всички са приключили. Array!

2 comments

  1. Нямам го целия код пред мен с който си тествал но, можеш ли да потвърдиш че svgAjaxArray не е array от Deffered обекти още от началото.
    Функцията apply( $, svgAjaxArray ) просто прави this-a в тялото на when фунцкциите закрепени към нея (в случая е само done но може да има и fail и т.н.) да е jquery обект.
    Друга особенност за apply() е че тя е част от core javascript и подозирам че в конкретния случай тя просто разбива на отделните Deffered обекти в масива и ги подава на when (в противен случай той се опитва да работи с един обект – масива съдържащ Deffered – ите).
    В този ред на мисли мисля, че дори да напишеш apply( null, svgAjaxArray ) кода пак ще работи.

  2. Здрасти,

    svgAjaxArray e array от Deffered обекти от самото начало, но като такъв това не го прави сам по себе си Deffered обект. T.e. ако го разглеждаме като promise то той взима своята стойност веднага когато той се създаде.

    Ползвам apply-а в случая за да мога да раздробя svjAjaxArray-а за да подам всеки един от елементите му като параметър на $.when. Наистина apply-а може да се използва за да се смени this-а, но в този случай аз не искам това и по тази причина искам да си го запазя такъв какъвто си е по подразбиране за $.when (т.е. $).

    Като го пробвах, наистина работи и ако дадеш за this null или undefined, но друг е въпроса, че за да си сигурен че няма да промениш начина по който работи функцията от която и да е библиотека е най-добре да подадеш контекста в който тя по принцип работи.

Leave a comment

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *

Този сайт използва Akismet за намаляване на спама. Научете как се обработват данните ви за коментари.