function imageContainer() {
this.selector = "img.inContainer";
this.width = function(cb) {
var tmp = 0;
var len = this.length;
var count = 0;
$(this.selector).each(function() {
// use load to preload images
var that = this;
// load is ajax so it is async
$(this).load(function() {
tmp += $(that).width();
if (++count === len) {
// counted all.
cb(tmp);
}
});
});
};
this.construct = function(cb) {
this.width(function(data) {
alert(data);
});
};
this.construct();
}
Добро пожаловать в ajax.Вы выполняете кучу операций параллельно асинхронно.Таким образом, вам нужно отслеживать, сколько завершено, и запускать обратный вызов, когда все завершено.
Любая асинхронная операция, такая как .load
, требует, чтобы вы либо блокировали на 100 секунд мс, либо изменили свой API для использования обратных вызовов.
Вместо шаблона var that = this
, который вы используетевместо этого также можно использовать $.proxy
.
// load is ajax so it is async
$(this).load($.proxy(function() {
tmp += $(this).width();
if (++count === len) {
// counted all.
cb(tmp);
}
}, this));
Поскольку у вас есть конструкция, позволяющая выполнить n ajax-задач перед запуском обратного вызова, вы можете обобщить это с помощью небольшого количества сахара.
this.width = function(cb) {
// map all images to deferred objects, when deferred objects are resolved
$.when($.makeArray($(this.selector).map(function() {
var def = $.Deferred();
$(this).load(function() {
def.resolve();
});
return def;
// then sum the widths and fire the callback.
}))).then($.proxy(function(data) {
var tmp = 0;
$(this.selector).each(function() {
tmp+=$(this).width();
});
cb(tmp);
}, this));
};
Обратите внимание, здесь я действительно хочу использовать $.fn.reduce
, но он не существует.Это могло бы быть
// reduce the set of images to the sum of their widths.
cb($(this.selector).reduce(0, function(memo, key, val) {
return memo + $(this).width();
}));
Если подумать, этот сахар не упрощает его, по крайней мере, теперь он больше похож на LISP, чем на C.