Javascript 从指令到服务的角度队列操作
我正试图更好地理解如何正确地在Angular中编码,并且正在编写自己的自定义模块,以便更好地理解应该如何工作 我有一个由图像和指令组成的HTML标记,即Javascript 从指令到服务的角度队列操作,javascript,angularjs,Javascript,Angularjs,我正试图更好地理解如何正确地在Angular中编码,并且正在编写自己的自定义模块,以便更好地理解应该如何工作 我有一个由图像和指令组成的HTML标记,即 <img ng-if="!post.tooBig" mydirective resize="0" ng-src="/img/@{{post.Content}}"> 想法是这样的:如果图像的文件名中附加了small,我知道它是一个缩略图。我想在后台加载它的大版本(同一个文件,没有附加的小文件),这样它就可以用于lightbox了 这
<img ng-if="!post.tooBig" mydirective resize="0" ng-src="/img/@{{post.Content}}">
想法是这样的:如果图像的文件名中附加了small
,我知道它是一个缩略图。我想在后台加载它的大版本(同一个文件,没有附加的小文件),这样它就可以用于lightbox了
这可以正常工作,但问题是,当我设置bigImage.src=source.replace(“small.”,“)时,我正在编译中完成所有工作代码>它会立即启动,如果页面上有许多小的
图像,它会导致页面速度减慢,因为正在进行的加载
因此,我想使用$q
使其一次加载一个图像
所以行动吧
var bigImage = new Image();
bigImage.src = source.replace("small.",".");
变成承诺。在指令中这样做是最佳实践吗?我的理解是这样做是没有意义的,我应该使用服务,但我不知道如何做到这一点。我可以更多地使用它,但我希望有更多经验的人能够指导我,像这样的最佳实践,以及类似工作流的代码示例,谢谢
编辑:
指令:
.directive('mydirective', [
'$animate','$mediaStack',
function($animate,$mediaStack) {
return {
restrict: 'A',
compile: function(tElement, tAttrs) {
return loader;
}
};
function loader(scope, element, attrs) {
var source = attrs.ngSrc;
var tooLoadBig = parseInt(attrs.resize);
if(tooLoadBig){
/*var bigImage = new Image();
bigImage.src = source.replace("small.",".");*/
$mediaStack.load(source);
}
}
}])
我的服务:
.factory('$mediaStack', [
'$animate', '$timeout', '$document', '$compile', '$rootScope',
'$q',
'$injector',
function($animate , $timeout , $document , $compile , $rootScope ,
$q,
$injector) {
var OPENED_MEDIA_CLASS = 'media-open';
var theImages = [];
$mediaStack = {};
$mediaStack.load = function(source){
theImages.push(source);
};
$mediaStack.loadRequest = function(theImages) {
deferred.resolve(function(){
var bigImage = new Image();
bigImage.src = theImages[0].replace("small.",".");
});
return deferred.promise;
}
/*var promise = asyncGreet('Robin Hood');
promise.then(function(greeting) {
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
}, function(update) {
alert('Got notification: ' + update);
});*/
//above from docs
}
return $mediaStack;
}])
这是因为它将图像URL获取到服务中的一个数组中,因此我拥有该数组中的所有图像,如何基于该数组正确使用$q
。我已经开始学习了,但是大部分的$mediaStack.loadRequest
都是基于文档的,我不知道在这种情况下如何有效地使用它
编辑2:
我的服务是:
.factory('$mediaStack', [
'$animate', '$timeout', '$document', '$compile', '$rootScope',
'$q',
'$injector',
function($animate , $timeout , $document , $compile , $rootScope ,
$q,
$injector) {
var OPENED_MEDIA_CLASS = 'media-open';
var theImages = [];
var theLoadedImages = [];
var thePromises = [];
var loading = false;
$mediaStack = {};
$mediaStack.load = function(source){
theImages.push(source);
var mainDeferred = $q.defer();
if(loading)
{
thePromises.push(mainDeferred.promise);
console.log(thePromises);
$mediaStack.myRaceFn(thePromises).then(function() {
console.log("Fire!");
loading=true;
$mediaStack.loadRequest(theImages[0]).then(function(bigImage){
console.log(bigImage);
theImages.shift();
theLoadedImages.push(bigImage);
loading = false;
mainDeferred.resolve();
});
});
}
if(!loading)
{
loading = true;
$mediaStack.loadRequest(theImages[0]).then(function(bigImage){
console.log(bigImage);
theImages.shift();
theLoadedImages.push(bigImage);
loading = false;
mainDeferred.resolve();
});
}
}
$mediaStack.loadRequest = function(source){
var deferred = $q.defer();
var bigImage = new Image();
bigImage.src = source.replace("small.",".");
bigImage.onload = function() {
deferred.resolve(bigImage);
}
return deferred.promise;
}
//.race implementation in old angular
$mediaStack.myRaceFn = function (promises){
return $q(function(resolve, reject) {
promises.forEach(function(promise) {
console.log(promise);
promise.then(resolve, reject);
});
});
}
//.race implementation in old angular
return $mediaStack;
}])
我非常接近,我看到了一系列的承诺,但我从来没有达到能够再次发射它们的程度,所以我有10张图片,我得到了9个承诺。我如何解雇他们
我以为会发生在这里:
$mediaStack.myRaceFn(thePromises).then(function() {
console.log("Fire!");
loading=true;
$mediaStack.loadRequest(theImages[0]).then(function(bigImage){
但是我从来没有得到过console.log()
相反,我在$mediaStack.myRaceFn()
中获得控制台消息,向我显示每个承诺(最后是9个),但它们只是坐在那里?我错过了一些东西
我想我可能太早了…我想,你的直觉很好。您需要一个服务来处理图像请求。请记住,浏览器仅限于向单个服务器/代理发送多个并发请求()
理论上,您可以创建一个promise,并通过双向绑定甚至使用属性驱动加载来公开它。比如:
HTML:
但我认为,这样的服务会更好。您可以从这一点决定加载内容和加载时间。它不会局限于UI组件,您可以加载更大的图像,而不仅仅是从指令上下文。
因此,在服务中,基本代码是:
module.factory('$mediaStack',['$q',function($q){//首先,您不需要所有这些依赖项,请保持列表简短
var imgDict={};//图像字典,我们将在其中信守承诺并加载图像
var loadingNow=0;
函数loadImage(img){
//发送请求并返回承诺
var deferred=$q.deferred();
var bigImage=新图像();
bigImage.onload=函数(){
延迟解析(bigImage);
}
bigImage.src=source.replace(“小“,”);
回报。承诺;
}
var$mediaStack=函数(img){
var deferred=$q.deferred();//主延迟任务
如果(loadingNow>4){//如果我们正在加载5个或更多图像,请将任务推迟到加载其中一个图像为止
var promissions=[];//承诺数组,现在正在加载的图像列表
Object.key(imgDict).forEach(函数(key){
如果(!(imgDict[key]instanceof Element)){//检查字典中的项是承诺还是加载的图像
promises.push(imgDict[key]);//如果是承诺,请将其添加到列表中
}
});
$q.race(promissions).then(function(){//使用列表创建一个竞赛:当一个承诺解决时(加载图像),我们可以再次启动我们的函数(我们可能同时加载的图像少于5个)
$mediaStack(img)。然后(函数(数据){//再次调用该函数
resolve(data);//当我们返回一个承诺表单时,我们必须解析主延迟对象
});
});
}
如果(!(img in imgDict)){//图像尚未加载时
loadingNow++;//增加正在加载的图像数量
imgDict[img]=loadImage(img)。然后(函数(imgDOM){//并加载映像
imgDict[img]=imgDOM;
deferred.resolve(imgDOM);//加载后解析主延迟任务
现在加载--;
});
}否则{
延期。解决(imgDict[img]);
}
return deferred.promise;//对主延迟任务的承诺
}
返回$mediaStack;
}]);代码>我认为,你的直觉很好。您需要一个服务来处理图像请求。请记住,浏览器仅限于向单个服务器/代理发送多个并发请求()
理论上,您可以创建一个promise,并通过双向绑定甚至使用属性驱动加载来公开它。比如:
HTML:
但我认为,这样的服务会更好。您可以从这一点决定加载内容和加载时间。它不会局限于UI组件,您可以加载更大的图像,而不仅仅是从指令上下文。
因此,在服务中,基本代码是:
module.factory('$mediaStack',['$q',function($q){//首先,您不需要所有这些依赖项,请保持列表简短
var imgDict={};//图像字典,我们将在其中信守承诺并加载图像
var loadingNow=0;
函数loadImage(img){
//发送请求并返回承诺
var deferred=$q.deferred();
var bigImage=新图像();
大形象。
$mediaStack.myRaceFn(thePromises).then(function() {
console.log("Fire!");
loading=true;
$mediaStack.loadRequest(theImages[0]).then(function(bigImage){
<img mydirective="booleanValue" />
$scope.$watch('mydirective', function (newVal, oldVal) {
if (newVal === true) {
//perform the load
}
});
.factory('$mediaStack', [
'$animate', '$timeout', '$document', '$compile', '$rootScope',
'$q',
'$injector',
function($animate , $timeout , $document , $compile , $rootScope ,
$q,
$injector) {
var OPENED_MEDIA_CLASS = 'media-open';
var theImages = [];
var theLoadedImages = [];
var thePromises = [];
var loading = false;
$mediaStack = {};
$mediaStack.load = function(source){
if(source)
{
theImages.push(source);
}
var mainDeferred = $q.defer();
if(loading)
{
thePromises.push(mainDeferred.promise);
console.log(thePromises);
$mediaStack.myRaceFn(thePromises).then(function() {
console.log("Fire!");
loading=true;
$mediaStack.loadRequest(theImages[0]).then(function(bigImage){
console.log(bigImage);
theImages.shift();
theLoadedImages.push(bigImage);
loading = false;
//mainDeferred.resolve();
});
});
}
if(!loading)
{
loading = true;
$mediaStack.loadRequest(theImages[0]).then(function(bigImage){
console.log(bigImage);
theImages.shift();
theLoadedImages.push(bigImage);
loading = false;
if(theImages.length>0)
{
$mediaStack.load();
};
});
}
}
$mediaStack.loadRequest = function(source){
var deferred = $q.defer();
var bigImage = new Image();
bigImage.src = source.replace("small.",".");
bigImage.onload = function() {
deferred.resolve(bigImage);
}
return deferred.promise;
}
//.race implementation in old angular
$mediaStack.myRaceFn = function (promises){
return $q(function(resolve, reject) {
promises.forEach(function(promise) {
console.log(promise);
promise.then(resolve, reject);
});
});
}
//.race implementation in old angular
return $mediaStack;
}])