Async AdHandler ou comment ne pas bloquer la page lors du chargement des pubs

Tagged:

Dans le cas ou on fonctionne avec un openX ou d'ailleurs avec n'importe quel serveur de pub je pense, il se peut que ce dernier ait des ralentissements. Selon la façon dont ça fonctionne, on insère un bout de code javascript qui en load un autre qui fait directement des document.write. Pas génial puisque si le serveur ralentit, le chargement de la page est bloqué a chaque pub. Pratique quand on a un leaderbord par exemple, ça nous fait une superbe page blanche et on attend ...

Ce que je me propose de faire c'est loader ces pub après coup malgré les document.write !

Donc comment faire ? Javascript est un language full-object, donc une fonction est un objet a part entière ... ça nous permet de faire notre propre fonction et de l'utiliser comme fonction document.write.

Du coup dans votre code, vous écrivez des div avec id unique, et une instruction qui va plus tard remplacer le div par la pub.

  1. <?php
  2. $uniq_id = rand(10000000, 90000000);
  3. $zones = array(
  4. 25 => 'a367b73f', /* leaderboard */
  5. 45 => 'a6f7bff6', /* other place */
  6. );
  7. ?>
  8.  
  9. <div id="advertise_<?php echo $uniq_id ?>"></div>
  10.  
  11. <script type='text/javascript'><!--//<![CDATA[
  12. if (typeof adhandler == "undefined") var adhandler = new AdHandler();
  13. adhandler.append(<?php echo $zone_id ?>, <?php echo $uniq_id ?>);
  14. //]]>--></script><noscript><a href="http://ads.monsite.com/www/delivery/ck.php?n=<?php echo $zones[$zone_id] ?>&amp;cb=<?php echo $uniq_id ?>" target="_blank"><img src="http://ads.monsite.com/www/delivery/avw.php?zoneid=<?php echo $zone_id ?>&amp;cb=<?php echo $uniq_id ?>&amp;n=<?php echo $zones[$zone_id] ?>" border="0" alt="" /></a></noscript>

Là j'en ai fait un partial symfony, du coup il me suffit de faire

  1. <?php echo get_partial('global/advertise', array('zone_id' => 25)); ?>

Et j'ai ma pub à l'endroit ou je veux ... Enfin pour l'instant j'ai juste un div et un peu de javascript, la mécanique qui se trouve derrière la voila :

  1. var AdHandler = Class.create({
  2.  
  3. init: function() {
  4. this.ads = new Array();
  5. this.ready = false;
  6. $(window).ready(function() {
  7. this.placeAll();
  8. this.ready = true;
  9. }.bind(this));
  10. },
  11.  
  12. append: function(zone_id, uniq_id) {
  13. this.ads.push({'zone_id': zone_id, 'uniq_id': uniq_id});
  14. if (this.ready) {
  15. this.placeAll();
  16. }
  17. },
  18.  
  19. placeAll: function() {
  20. this.place();
  21. },
  22.  
  23. place: function() {
  24. this.actual = this.ads.pop();
  25. this.oldFunction = document.write;
  26. document.write = this.documentWrite.bind(this);
  27.  
  28. $.ajax({
  29. url: this.getUrl(),
  30. dataType: "script",
  31. async: false,
  32. success: function(js){if(jQuery.browser.safari){eval(js);}}
  33. });
  34. },
  35.  
  36. documentWrite: function(text) {
  37. $('#advertise_' + this.actual['uniq_id']).replaceWith(text);
  38. document.write = this.oldFunction;
  39. if (this.ads.length > 0) this.placeAll();
  40. },
  41.  
  42. getUrl: function() {
  43. var m3_u = (location.protocol=='https:'?'https://ads.monsite.com/www/delivery/ajs.php':'http://ads.monsite.com/www/delivery/ajs.php');
  44. var m3_r = Math.floor(Math.random()*99999999999);
  45. if (!document.MAX_used) document.MAX_used = ',';
  46.  
  47. url = m3_u;
  48. url += '?zoneid=' + this.actual['zone_id'];
  49. url += '&amp;cb=' + m3_r;
  50. if (document.MAX_used != ',') url += '&amp;exclude=' + document.MAX_used;
  51. url += '&amp;loc=' + escape(window.location);
  52. if (document.referrer) url += '&amp;referer=' + escape(document.referrer);
  53. if (document.context) url += '&context=' + escape(document.context);
  54. if (document.mmm_fo) url += '&amp;mmm_fo=1';
  55.  
  56. return url;
  57. }
  58.  
  59. });

La fonction getUrl construit une URL de la même manière que le fait le script d'origine de openX. Au courant de la page on fait des append qui simplement rajoutent dans la pile l'association entre la zone et le div.

Le placeAll va parcourir la liste des couple zone/div... enfin parcourir ... si on peut dire ... pour éviter que le tout se bouffe le nez j'ai fais ça plus séquentiellement, donc on a une fonction place qui dépop un élément remplace la fonction document.write et appelle le javascript. Le javascript fait sont document.write qui est donc le notre pour le coup et qui place le text au bon endroit, rétabli la fonction document.write originale et poursuit la liste si besoin est !

Et la je me rend compte que écrire du code c'est beaucoup plus simple que d'écrire des phrases qui expliquent le code ! En tout cas ça marche plutot pas trop mal c'est bientot en prod ;-)