Jquery promise implements image loading one by one

  • 2020-10-23 20:53:39
  • OfStack

Promise is specification 1 of CommonJS, with resolve, reject, done, fail, then and other methods, which can help us control the flow of code and avoid multi-layer nesting of functions. Asynchronism is becoming more and more important in web development. For developers, this kind of non-linear programming can be difficult to control, while Promise gives us more control over the execution process of the code. Popular js libraries such as jQuery already implement this object, and ES6, which will be released later this year, will implement Promise native.

In the javascript design pattern practice of the proxy mode - image preloading using the proxy mode to realize the image preloading function.

Now take it one step further and complete a feature that allows you to load successive images one by one.

Function:

1.1 One loading picture.

2. Loading error. After timeout, images of failed loading are displayed.

For functional requirements, there is bound to be handling of loadstate events and final-time callbacks, which not only creates code clutter, but also breaks principles that are no longer written in the usual way. In view of the characteristics of this status notification, it is more appropriate to adopt promise architecture for processing. promise is essentially one of the subscription publish design patterns. Currently, this function is developed with promise which comes with jquery.

1. Complete 1 agent creation function to load the image, which can generate 1 agent with load timeout, failure, success and cancellation monitoring capability.


 function createLoadImgProxy(){
  var imgCache = new Image();
  var dfd = $.Deferred();
  var timeoutTimer;
  // Start loading timeout monitoring and proceed after timeout reject operation 
  function beginTimeoutWatcher(){
   timeoutTimer = setTimeout(function(){
   dfd.reject('timeout');
   }, 10000);
  }
  // End load timeout monitoring 
  function endTimeoutWatcher(){
   if(!timeoutTimer){
   return;
   }
   clearTimeout(timeoutTimer);
  }
  // Load completion event processing, after the load is completed resolve operation 
  imgCache.onload = function(){
   dfd.resolve(this.src);
  };
  // Load termination event processing, after termination reject operation 
  imgCache.onabort = function(){
   dfd.reject("aborted");
  };
  // Load exception event handling, after the exception reject operation 
  imgCache.onerror = function(){
   dfd.reject("error");
  };
  return function(eleImg, src){
   dfd.always(function(){
   // The load timeout monitoring is terminated when the load completes or fails 
   endTimeoutWatcher();
   }).done(function(src){
   // When the load is complete, set the image on the image element 
   loadImg(eleImg, src);
   }).fail(function(msg){
   // After failing to load, set the failed image to the image element 
   loadImg(eleImg, 'loadFailed.jpg');
   });
   loadImg(eleImg, 'loading.gif');
   imgCache.src = src;
   // Timeout loading monitoring begins 
   beginTimeoutWatcher();
   return dfd.promise();
  };
  }

An Deferred object is created as follows


var dfd = $.Deferred();

The Deferred object fires the completion event through the resolve method, and the done method responds to the completion event.

The completion event when the load succeeds.


   imgCache.onload = function(){
                    dfd.resolve(this.src);
                };

And the response processing when the load is complete, which is to set the image to the element, the following code is the above chain of the demolition.


   dfd.done(function(src){
                        // When the load is complete, set the image on the image element
                        loadImg(eleImg, src);
                    });

The Defferred object fires the rejection event via the reject method and USES the fail method to respond to the rejection event, indicating that the load failed.

Reject event during load timeout, termination, exception.


 // Start loading timeout monitoring and proceed after timeout reject operation 
  function beginTimeoutWatcher(){
   timeoutTimer = setTimeout(function(){
   dfd.reject('timeout');
   }, 10000);
  }
  // Load termination event processing, after termination reject operation 
  imgCache.onabort = function(){
   dfd.reject("aborted");
  };
  // Load exception event handling, after the exception reject operation 
  imgCache.onerror = function(){
   dfd.reject("error");
  };

And the response processing when the load failed to set the failed image.


 dfd.fail(function(msg){
   // After failing to load, set the failed image to the image element 
   loadImg(eleImg, 'loadFailed.jpg');
   });

At the end of the proxy function, the promise object of deferred is returned to monitor the completion and failure states of the load at the point of call, so that the next image is loaded.

return dfd.promise();

2.1 Continuous one-sheet loading


//1 zhang 1 A continuous load of pictures 
  // Parameters: 
  // srcs:  Image path array 
  function doLoadImgs(srcs){
  var index = 0;
  (function loadOneByOne(){
   // Exit criteria 
   if(!(s = srcs[index++])) {
   return;
   }
   var eleImg = createImgElement();
   document.getElementById('imgContainer').appendChild(eleImg);
   // create 1 A load proxy function 
   var loadImgProxy = createLoadImgProxy();
   // After the current picture loads or fails, recursively call under load 1 zhang 
   loadImgProxy(eleImg, s).always(loadOneByOne);
  })();
  }

Do a load recursive function for loadOneByOne.

Internally, 1 loading agent is created. After the agent loads the image, no matter it succeeds or fails, it recursively calls the loadOneByOne function to load the next image.

The key lies in the promise object returned by the proxy function. The.always method can be used to make a recursive call to loadOneByOne to load the next slide after it has been loaded (successfully or not).


loadImgProxy(eleImg, s).always(loadOneByOne);

That's it.

With the adoption of the promise mode, the callback function is gone, as are the functions that maintain state and internal variables, and the code is clearer and simpler, so that the 1 consistency between the proxy function and the local function is protected.

Complete code:


<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 </head>
 <body>
 <button id='btnLoadImg'> Loading pictures </button>
 <br>
 <div id='imgContainer'>
 </div>
 <br>
 <script type='text/javascript' src="./jquery-1.11.3.min.js"></script>
 <script type='text/javascript'>
  var imgSrcs = [
  'http://img.wanchezhijia.com/A/2015/3/20/17/11/de63f77c-f74f-413a-951b-5390101a7d74.jpg',
  'http://www.newbridgemotorsport.com/files/6413/9945/0406/IMG_3630.jpg',
  'http://www.carsceneuk.com/wp-content/uploads/2015/03/88y9989.jpg',
  'http://mfiles.sohu.com/20130223/5ff_403b2e7a_7a1f_7f24_66eb_79e3f27d58cf_1.jpg',
  'http://img1.imgtn.bdimg.com/it/u=2678963350,1378052193&fm=21&gp=0.jpg'
  ];
  $(document).ready(function(){
  $('#btnLoadImg').bind('click', function(){
   doLoadImgs(imgSrcs);
  });
  });
  // create img The label 
  // I'm going to use the self-executing function plus 1 A closure, so that multiple can be created id different img The label. 
  var createImgElement = (function(){
  var index = 0;
  return function() {
   var eleImg = document.createElement('img');
   eleImg.setAttribute('width', '200');
   eleImg.setAttribute('heght', '150');
   eleImg.setAttribute('id', 'img' + index++);
   return eleImg;
  };
  })();
  function loadImg(img, src) {
  img.src = src;
  }
  function createLoadImgProxy(){
  var imgCache = new Image();
  var dfd = $.Deferred();
  var timeoutTimer;
  // Start loading timeout monitoring and proceed after timeout reject operation 
  function beginTimeoutWatcher(){
   timeoutTimer = setTimeout(function(){
   dfd.reject('timeout');
   }, 10000);
  }
  // End load timeout monitoring 
  function endTimeoutWatcher(){
   if(!timeoutTimer){
   return;
   }
   clearTimeout(timeoutTimer);
  }
  // Load completion event processing, after the load is completed resolve operation 
  imgCache.onload = function(){
   dfd.resolve(this.src);
  };
  // Load termination event processing, after termination reject operation 
  imgCache.onabort = function(){
   dfd.reject("aborted");
  };
  // Load exception event handling, after the exception reject operation 
  imgCache.onerror = function(){
   dfd.reject("error");
  };
  return function(eleImg, src){
   dfd.always(function(){
//   alert('always end');
   // The load timeout monitoring is terminated when the load completes or fails 
   endTimeoutWatcher();
   }).done(function(src){
//   alert('done end');
   // When the load is complete, set the image on the image element 
   loadImg(eleImg, src);
   }).fail(function(msg){
//   alert('fail end:' + msg);
   // After failing to load, set the failed image to the image element 
   loadImg(eleImg, 'loadFailed.jpg');
   });
   loadImg(eleImg, 'loading.gif');
   imgCache.src = src;
   // Timeout loading monitoring begins 
   beginTimeoutWatcher();
   return dfd.promise();
  };
  }
  //1 zhang 1 A continuous load of pictures 
  // Parameters: 
  // srcs:  Image path array 
  function doLoadImgs(srcs){
  var index = 0;
  (function loadOneByOne(){
   // Exit criteria 
   if(!(s = srcs[index++])) {
   return;
   }
   var eleImg = createImgElement();
   document.getElementById('imgContainer').appendChild(eleImg);
   // create 1 A load proxy function 
   var loadImgProxy = createLoadImgProxy();
   // After the current picture loads or fails, recursively call under load 1 zhang 
   loadImgProxy(eleImg, s).always(loadOneByOne);
  })();
  }
 </script>
 </body>
</html>

Related articles: