2014-02-28 101 views
0

我使用以下代码预加载专辑图像并显示加载栏。setTimeout预加载图像时

var album1 = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg']; 
var album2 = ['01.jpg', '02.jpg', '03.jpg', '04.jpg', '05.jpg']; 
var total_images = album1.length + album2.length; 
var load_count = 0; 

$(document).ready(function() { 
    function preloadImages(list, path) { 
     var img; 
     if (!preloadImages.cache) { 
      preloadImages.cache = []; 
     } 
     for (var i = 0; i < list.length; i++) { 
      img = new Image(); 
      $(img).bind('load', function() { 
       load_count++; 
       $('#loading_bar #progress').css('width', Math.round(load_count * 100/total_images) + '%'); 
       if(load_count >= total_images) { 
        init_sequence(); 
       } 
      }); 
      img.src = path + list[i]; 
      preloadImages.cache.push(img); 
     } 
    } 

    preloadImages(album1, 'http://www.example.com/images/path1/'); 
    preloadImages(album2, 'http://www.example.com/images/path2/'); 
} 

上述预加载代码在正常网络条件下工作正常。但是,如果网络不稳定,使其中一个图像无法加载,则无法触发功能init_sequence()

我的问题是,如何在预加载图像时设置超时(可能在上述函数中使用setTimeout())(例如,如果预加载无法在30秒内完成,反正加载init_sequence())?


附加信息:

如果有人需要知道的HTML结构,这(让我只显示<body>一部分,我已经包括jQuery的肯定):

<body> 
    <div id="loading_bar"> 
    <div id="progress"></div> 
    </div> 
</body> 

和CSS:

#loading_bar { 
    position: fixed; 
    left: 0; 
    bottom: 0; 
    height: 5px; 
    width: 100%; 
    background-color: #EEE; 
} 
#loading_bar #progress { 
    position: relative; 
    left: 0; 
    height: 5px; 
    width: 0; 
    background-color: #A68029; 
} 
+0

这并不难。我的意思是你必须创建一个你的文件名的目录,并在30秒后检查每个文件是否加载到目录中。无论何时注册文件,但未加载文件,都可以删除文件,并仅显示其他文件。你有什么问题?在JS中为 – inf3rno

+0

,图片仍然可以在没有预加载的情况下被加载,但是当用户输入正在加载大量图片的页面时,用户体验并不好。 – Raptor

+0

好的,然后只需添加一个名为'initialized'的加号变量,并在30秒后检查它是真是假。你应该通过调用init来设置它。如果30秒后它不是真的,请调用init。 – inf3rno

回答

2

只需使用下面的超时变量即可。

var album1 = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg']; 
var album2 = ['01.jpg', '02.jpg', '03.jpg', '04.jpg', '05.jpg']; 
var total_images = album1.length + album2.length; 
var load_count = 0; 



$(document).ready(function() { 
    // A flag to check if loading timeout had been reached 
    var loadTimeout = false; 

    function preloadImages(list, path) { 

     var img; 
     if (!preloadImages.cache) { 
      preloadImages.cache = []; 
     } 
     for (var i = 0; i < list.length; i++) { 
      img = new Image(); 
      $(img).bind('load', function() { 
       load_count++; 
       $('#loading_bar #progress').css('width', Math.round(load_count * 100/total_images) + '%'); 
       if(load_count >= total_images) { 
        // If we get this far, then clear the timeout variable 
        clearTimeout(timeout); 

        // If the image is loaded after timeout, then do nothing because init_sequence have been called. 
        if (loadTimeout == false) { 
         init_sequence(); 
        } 
       } 
      }); 
      img.src = path + list[i]; 
      preloadImages.cache.push(img); 
     } 
    } 
    // Set timeout for 30 seconds 
    var timeout = setTimeout(function() { 
     loadTimeout = true; 
     init_sequence(); 
    }, 30000); 
    preloadImages(album1, 'http://www.example.com/images/path1/'); 
    preloadImages(album2, 'http://www.example.com/images/path2/'); 
} 
+0

谢谢,这可能适用!让我尝试。 – Raptor

+0

请记住,如果在30秒超时后所有映像加载成功,可能会在此处多次调用init_sequence。您可以删除处理程序,也可以忽略后续的'init_sequence'调用。 – plalx

+0

@plalx我确实使用过'clearTimeout(timeout);'你注意到了吗?或者我错过了什么? – TrungDQ

0
var initialized = false; 
function init_sequence(){ 
    if (initialized) 
     return; 
    initialized = true; 
    //... 
} 

setTimeout(init_sequence, 30000); 

那么在我的情况下,它会是这样的(或者我会使用的承诺,而不是观察者),我喜欢OO ......但我不认为这是可以接受的你;-)

var Observer = function(){ 
    this.listeners = {}; 
}; 
Observer.prototype = { 
    constructor: Observer, 
    register: function (type){ 
     this.listeners[type] = []; 
    }, 
    on: function (type, callback){ 
     this.listeners[type].push(callback); 
    }, 
    off: function (type){ 
     this.listeners[type].length = 0; 
    }, 
    trigger: function (type){ 
     var args = Array.prototype.slice.call(arguments, 1); 
     var listeners = this.listeners[type]; 
     for (var i=0, l=listeners.length; i<l; ++i){ 
      var listener = listeners[i]; 
     } 
    } 
}; 

var Map = function(){ 
    this.data = {}; 
}; 
Map.prototype = { 
    constructor: Map, 
    length: 0, 
    set: function (key, value){ 
     if (!this.has(key)) 
      ++this.length; 
     this.data[key] = value; 
    }, 
    has: function (key){ 
     return this.data.hasOwnProperty(key); 
    }, 
    get: function (key){ 
     if (this.has(key)) 
      return this.data[key]; 
    }, 
    remove: function (key){ 
     if (this.has(key)) 
      --this.length; 
     delete(this.data[key]); 
    }, 
    each: function (callback){ 
     for (var key in this.data) 
      if (this.has(key)) 
       callback(this.get(key), key); 
    } 
}; 

var ImagePreloader = function(){ 
    this.loaded = new Map(); 
    this.loading = new Map(); 
    this.observer = new Observer(); 
    this.observer.register("progress"); 
    this.observer.register("complete"); 
}; 
ImagePreloader.prototype = { 
    constructor: ImagePreloader, 
    on: function (type, callback){ 
     this.observer.on(type, callback); 
    }, 
    off: function (type){ 
     this.observer.off(type); 
    }, 
    trigger: function (type){ 
     this.observer.trigger.apply(this.observer, arguments); 
    }, 
    percent: function(){ 
     var totalCount = this.loading.length + this.loaded.length; 
     if (!totalCount) 
      return 0; 
     return Math.round(100 * this.loading.length/totalCount); 
    }, 
    load: function (url){ 
     if (this.loading.has(url) || this.loaded.has(url)) 
      return; 
     var image = new Image(); 
     this.loading.set(url, image); 
     $(image).bind("load", function() { 
      this.success(url); 
     }.bind(this)); 
     image.src = url; 
     this.progress(); 
    }, 
    success: function (url){ 
     var image = this.loading.get(url); 
     this.loading.remove(url); 
     this.loaded.set(url, image); 
     this.progress(); 
    }, 
    progress: function(){ 
     var percent = this.percent(); 
     this.observer.trigger("progress", percent); 
     if (percent == 100) 
      this.observer.trigger("complete"); 
    } 
} 

var ProgressBar = function(){ 
}; 
ProgressBar.prototype = { 
    constructor: ProgressBar, 
    $el: null, 
    percent: 0, 
    setElement: function (el){ 
     this.$el = $(el); 
    }, 
    setProgress: function (percent){ 
     this.percent = percent; 
    }, 
    render: function(){ 
     if (!this.$el) 
      return; 
     this.$el.css("width", this.percent + "%"); 
    } 
}; 

var Album = function (baseUrl, pathes){ 
    this.baseUrl = baseUrl || "/"; 
    this.images = new Map(); 
    if (pathes) 
     this.pushAll(pathes); 
}; 
Album.prototype = { 
    constructor: Album, 
    length: 0, 
    pushAll: function (pathes){ 
     for (var i=0, l=pathes.length; i<l; ++i) 
      this.push(images[i]); 
    }, 
    push: function (path){ 
     var url = baseUrl + path; 
     this.images.set(path, url); 
     this.length = this.images.length; 
    }, 
    each: function (callback){ 
     this.images.each(callback); 
    } 
}; 

var Main = { 
    run: function(){ 
     var albums = this.createAlbums(); 
     this.preloadAlbums(albums, this.renderAlbums.bind(this)); 
    }, 
    createAlbums: function(){ 
     var albums = new Map(); 
     albums.set("album1", new Album(
      'http://www.example.com/images/path1/', 
      ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg'] 
     )); 
     albums.set("album2", new Album(
      'http://www.example.com/images/path2/', 
      ['01.jpg', '02.jpg', '03.jpg', '04.jpg', '05.jpg'] 
     )); 
     return albums; 
    }, 
    preloadAlbums: function (albums, complete){ 
     var timeoutSeconds = 30; 
     var progressBar = new ProgressBar(); 
     $(document).ready(function() { 
      progressBar.setElement('#loading_bar #progress'); 
     }); 
     var preloader = new ImagePreloader(); 
     preloader.on("progress", function (percent){ 
      progressBar.setProgress(percent); 
      progressBar.render(); 
     }); 
     preloader.on("complete", function(){ 
      preloader.off("complete"); 
      complete(albums); 
     }); 
     albums.each(function (album){ 
      album.each(function (url){ 
       preloader.load(url); 
      }); 
     }); 
     setTimeout(function(){ 
      preloader.trigger("complete"); 
     }, timeoutSeconds * 1000); 
    }, 
    renderAlbums: function (albums){ 
     init_sequence(); 
    } 
}; 

Main.run(); 

Btw。我不认为你必须等到ready开始预加载图像...

+0

澄清:'init_sequence()'是一系列的动画。当我在'preloadImages()'中完成加载图像时,我调用'init_sequence()'开始动画。我只是无法弄清楚这个代码可以合并我目前的逻辑。 – Raptor

+0

你可以在调用'init_sequence'之前检查'initialized'。我只是不想复制粘贴你的整个代码... – inf3rno