[英]Is this a correct way to use the Deferred object?
I'm building a App that need to list the categories and subcategories of a Product. 我正在构建一个需要列出产品类别和子类别的应用程序。
When a user selects a category, the subcategories related to this category are loaded from the server with ajax, but only if they have not been loaded later (in this case they are loaded from the DOM). 当用户选择一个类别时,与此类别相关的子类别将使用ajax从服务器加载,但前提是以后没有加载(在这种情况下,它们是从DOM加载的)。
Code: http://jsbin.com/abijad/edit#javascript,html 代码: http : //jsbin.com/abijad/edit#javascript,html
var $form = $('#new-product-form');
$form.on( 'change', 'select.product-categories', function( e ) { //I'm using event delegation for a future feature...
getSubCategories( $(this).val() ).done( function( $subCategoriesEl ){
$form.find( 'select.product-subcategories' ).not( $subCategoriesEl ).hide();
$subCategoriesEl.show();
});
});
var getSubCategories = function( categoryId ) {
var dfd = $.Deferred(),
$alreadyisLoaded = $form.find( 'select.product-subcategories' ).map( function( idx, el ){
if( parseInt( $( this ).data( 'category' ), 10 ) === parseInt( categoryId, 10 ) ){
return el;
}
});
if( $alreadyisLoaded.length > 0 ){ //don't request subCategories that already are loaded
console.log( 'SubCategory loaded from DOM' );
dfd.resolve( $alreadyisLoaded );
} else {
var subCategoriesHtml = '<select data-category="' + categoryId + '" class="product-subcategories">';
$.get( '/', { //The ajax request will only be simulated
categoryId : categoryId
}, function ( result ) {
//simulate success :X
result = {"status":1,"data":[{"name":"Sub-Category I","id":1},{"name":"Sub-Category II","id":2},{"name":"Sub-Category III","id":3}]};
console.log( 'SubCategory loaded with Ajax' );
if( result.status === 1 ) { //Success
for( var subCategoryInfo in result.data) {
if( result.data.hasOwnProperty( subCategoryInfo ) ){
subCategoriesHtml += '<option value="' + result.data[subCategoryInfo].id + '">';
subCategoriesHtml += result.data[subCategoryInfo].name + '</option>';
}
}
subCategoriesHtml += '</select>';
var $subCategories = $( subCategoriesHtml ).hide().appendTo( $form );
dfd.resolve( $subCategories );
} else {
dfd.reject();
}
});
}
return dfd.promise();
};
<form id="new-product-form">
<select class="product-categories">
<option value="1">Category I</option>
<option value="2">Category II</option>
<option value="3">Category III</option>
<option value="4">Category IV</option>
<option value="5">Category V</option>
</select>
<select data-category="1" class="product-subcategories">
<option value="1">SubCategory I</option>
<option value="2">SubCategory II</option>
<option value="3">SubCategory III</option>
<option value="4">SubCategory IV</option>
<option value="5">SubCategory V</option>
</select>
</form>
Because the code was getting full of callback here and there, I decided to use the jQuery Deferred object, but I do not know if this is the correct implementation. 因为代码到处都是回调,所以我决定使用jQuery Deferred对象,但是我不知道这是否是正确的实现。 Could someone tell me I did the right thing, or should I do differently?
有人可以告诉我我做了正确的事,还是我应该做不同的事情?
I don't see anything glaringly incorrect. 我看不到任何明显不正确的内容。 All in all, you are using the deferred in the correct fashion: to abstract away the possibly dual-synchronistic nature of your method.
总而言之,您以正确的方式使用deferd:抽象出方法的可能双重同步特性。 Now, that being said, if this were code appearing in my codebase, this is how I would write it.
话虽如此,如果这是我的代码库中出现的代码,这就是我的编写方式。 The main points being: don't use
for in
on arrays, build strings with arrays, consistent naming and spacing, and just some other terse JS preferences. 主要要点是:不要在数组中使用
for in
,不要用数组构建字符串,一致的命名和间距,以及其他一些简洁的JS首选项。 These are a matter of taste, so otherwise, good job: 这些只是一个口味问题,因此,做得很好:
(function() {
var getSubCategories = function ( categoryId ) {
categoryId = +categoryId;
return $.Deferred( function ( dfd ) {
var isLoaded = form.find( 'select.product-subcategories' )
.map( function ( index, el ) {
if ( +$( this ).data( 'category' ) === categoryId ) {
return el;
}
}),
markup = [ ];
if ( isLoaded.length ) {
console.log( 'SubCategory loaded from DOM' );
dfd.resolve( isLoaded );
} else {
markup.push( '<select data-category="' + categoryId + '" class="product-subcategories">' );
var request = $.ajax({
url: '/',
data: { categoryId: categoryId }
});
request.done( function ( result ) {
//simulate success :X
result = {"status":1,"data":[{"name":"Sub-Category I","id":1},{"name":"Sub-Category II","id":2},{"name":"Sub-Category III","id":3}]};
var status = result.status,
data = result.data,
i = 0,
il = data.length,
current;
console.log( 'SubCategory loaded with Ajax' );
if ( status !== 1 || !data ) {
dfd.reject();
return;
}
for ( current = data[ i ]; i < il; i++ ) {
markup.push( '<option value="' + current.id + '">' );
markup.push( current.name + '</option>' );
}
markup.push( '</select>' );
dfd.resolve( $( markup.join( '' ) ).hide().appendTo( form ) );
});
}
}).promise();
};
var form = $( '#new-product-form' )
.on( 'change', 'select.product-categories', function ( e ) {
getSubCategories( $( this ).val() )
.done( function( el ) {
form.find( 'select.product-subcategories' )
.not( el )
.hide()
el.show();
});
});
});
As a side note, just wanted to bring up that you don't have any handling of problems if the ajax request fails. 附带说明一下,只是想提出一点,如果ajax请求失败,您将不会处理任何问题。 You would need to
reject
in that case, and make sure you write fail
methods. 在这种情况下,您将需要
reject
,并确保编写fail
方法。 Just a heads up. 只是抬头。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.