###前提・実現したいこと
<button>
クリック時に以下の順で処理したいです。
1.<section>
をfadeOut()
2.<section>
に<div>
を挿入
3.<div>
に「Ajaxデータ」を挿入
###発生している問題
Ajaxの処理が早い場合に困った事態になりました。
fadeOut()
が終わってやっと存在する<div
>なのですが、もしAjaxがfadeOut()
より早く終わると、「<div>
なんてないから「Ajaxデータ」を挿入できないよ」となるんです。
###該当のソースコード
この流れです。
実際に動かせるように、AjaxでなくsetTimeOutで書いています。
問題は★の数値(jsfiddleでいう21行目)で、これがAjaxの処理速度(つまりsetTiemout速度)を示すのですが、もしfadeOut()
より早い場合に問題が生じます。
???? https://jsfiddle.net/v8pmcsak/
HTML
1<main> 2 <section> 3 <!-- Ajaxデータを反映したHTMLが挿入される --> 4 </section> 5</main> 6<button data-area="one">Pjax one</button> 7<button data-area="two">Pjax two</button>
jQeury
1$('button').click(function(){ 2 const area = $(this).attr('data-area'); 3 Pjax(area); 4}); 5 6function Pjax(area){ 7/* 8Ajaxの処理が早い場合だと 9(つまり21行目の★がフェードより早い場合だと) 10「Ajaxデータ」がHTMLに反映できない 11*/ 12 13 // 表示切替 14 $('body').append('<p class="loading">loading</p>') 15 $('section').fadeOut(1000, function(){ 16 var html = getHtml(area); 17 $('section').html(html); 18 }); 19 20 $.Deferred().resolve().then(function() { 21 return getAjaxData(100); // ★ 22 }) 23 .then(function(ajaxData) { 24 console.log(ajaxData); 25 $('body').find('.loading').remove(); 26 $('section').find('div[data-area="'+area+'"]').html('<p>'+ajaxData+'</p>'); 27 $('section').fadeIn(1000, function(){ 28 //history.pushState(location.href); 29 }); 30 }); 31} 32 33function getAjaxData(delay){ 34 const d = new $.Deferred; 35 setTimeout(function(){ // テストのためAjaxの代わりにsetTimeOut 36 const ajaxData = 'Ajaxデータ'; 37 d.resolve(ajaxData); 38 }, delay); 39 return d.promise(); 40} 41 42function getHtml(area){ 43 let html; 44 if( area == 'one' ){ 45 html = `<div data-area="one"></div>`; 46 } 47 else if( area == 'two' ){ 48 html = `<div data-area="two"></div>`; 49 } 50 return html; 51}
###試したこと
まず★の数値を大きくした場合に問題が生じませんでした。
たとえば上はfadeOut(1000)
に対して★が100
ですが、★を1001
にしたらちゃんと「Ajaxデータ」が表示され問題は生じません。
あとあらかじめ<section>
に<div>
を書いてやれば、やはり問題は生じません。
以上2点からAjaxの処理速度が原因だ!と思い込んでいますが、もしかしたら他の原因かもしれません。
どうすればAjaxの処理速度にかかわらず、実現したい順番で処理できるでしょうか。
###試したこと(追記)
ご回答の中に
$.Deferred().resolve().then(function() {
ではなく
$.when()
を使えとのアドバイスを頂きました。
その理由として自分なりに推測したのは、
3.<div>
に「Ajaxデータ」を挿入
のために待たなければならない処理が
1.<section>
をfadeOut()
2.<section>
に<div>
を挿入
と2つあり、
そのように複数の処理を待つ場合は$.Deferred().resolve().then(function() {
では対応できないためだと考えました。
以上のように考え、修正したのが次のコードです。【変更➀】と【変更➁】が上の推測に沿った修正になります。
jQeury
1$('button').click(function(){ 2 const area = $(this).attr('data-area'); 3 Pjax(area); 4}); 5 6function Pjax(area){ 7 8 // 表示切替 9 $('body').append('<p class="loading">loading</p>'); 10 11 /* 12 【変更➀】 13 この部分を myFadeOut() と関数化し、getAjaxData() の場所に書いてみました 14 $('section').fadeOut(1000, function(){ 15 var html = getHtml(area); 16 $('section').html(html); 17 }); 18 */ 19 20 /* 21 【変更➁】 22 2つの処理完了を待つため $.when().done() に変更しました 23 */ 24 $.when( 25 myFadeOut(area,1000), getAjaxData(100) 26 ) 27 .done(function(ajaxData) { 28 console.log(ajaxData); 29 $('body').find('.loading').remove(); 30 $('section').find('div[data-area="'+area+'"]').html('<p>'+ajaxData+'</p>'); 31 $('section').fadeIn(1000, function(){ 32 //history.pushState(location.href); 33 }); 34 }); 35} 36 37// 【変更➀】の関数 38function myFadeOut(area,dalution){ 39 const d = new $.Deferred; 40 $('section').fadeOut(dalution, function(){ 41 var html = getHtml(area); 42 $('section').html(html); 43 d.resolve(); 44 }); 45 return d.promise(); 46} 47 48function getAjaxData(delay){ 49 const d = new $.Deferred; 50 setTimeout(function(){ // テストのためAjaxの代わりにsetTimeOut 51 const ajaxData = 'Ajaxデータ'; 52 d.resolve(ajaxData); 53 }, delay); 54 return d.promise(); 55} 56 57function getHtml(area){ 58 let html; 59 if( area == 'one' ){ 60 html = `<div data-area="one"></div>`; 61 } 62 else if( area == 'two' ){ 63 html = `<div data-area="two"></div>`; 64 } 65 return html; 66}
ですが、、これでもできず、再び限界になりここに追記させて頂きました。
解決できる方がいらっしゃいましたらご回答頂けましたら幸いです。
回答2件
あなたの回答
tips
プレビュー