質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

2回答

1301閲覧

jsのasync/awaitを使ってアニメーション終了後に

Anon_

総合スコア334

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2019/03/11 00:31

編集2019/03/11 04:07

JSのasync/awaitを使ってフェードアニメーション完了後にログにOKと出す処理を書いたいのですが、
アニメーションが動いてる最中にOKと出力されてしまいます。
下記の修正すべき点をご指摘いただけませんでしょうか。

<script> jQuery( function($){ $(".home .s3 .box").css("position","absolute"); $(window).on("load scroll resize", function(){ asyncFunction(); }); function promiseIncrement() { return new Promise((resolve) => { $(".as").each(function(i){ var imgPos = $(this).offset().top; var scroll = $(window).scrollTop(); var windowHeight = $(window).height(); if (scroll > imgPos - windowHeight + windowHeight / 3){ // ここに処理を書く $(this).delay(200).css("visibility","visible").animate({opacity: 1}, 1000); } console.log(i); }); resolve(); //処理が完了したことを通知 }); } async function asyncFunction(x) { // await で Promise の解決を待つ const n = await promiseIncrement(); console.log('OK'); $(".home .s3 .box").css('position', 'relative'); } }); </script>

編集
下記のコードで期待する動作となりました。

$(".home .s3 .box").css("position","absolute"); $(window).on("load scroll resize", function(){ promiseIncrement(); }); function promiseIncrement() { var deferredArr = []; $(".as").each(function(i){ var imgPos = $(this).offset().top; var scroll = $(window).scrollTop(); var windowHeight = $(window).height(); if (scroll > imgPos - windowHeight + windowHeight / 3){ // ここに処理を書く deferredArr.push( $(this).delay(200*i).css("visibility","visible").animate({opacity: 1}, 1000)); } }); if( deferredArr.length > 0 ){ $.when.apply( $,deferredArr ).done(function(){ console.log('OK'); }); } } ```

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2019/03/11 00:37

HTMLも明示ください
Lhankor_Mhy

2019/03/11 03:12

「アニメーションが200msごとでなく一気に実行されるようになりました」とありますが、ぱっと見だと元のコードでも同様ではないですかね……?
Lhankor_Mhy

2019/03/11 03:21

(もしかして、実際のコードでは delay(200*i) と書かれているとか……?)
Anon_

2019/03/11 04:04

あぁ! まさにその通りですTT 最初に記載したコードが既に間違っておりました・・・。 修正して再度試してみたいと思います。
Anon_

2019/03/11 04:34

修正したコードでいけたと思ったんですが、アニメーションの最中にスクロールすると次の処理がはしってdeferredArrが空になるためなのか、if( deferredArr.length > 0 ){でヒットしなくなってしまいました。 JS難しい・・・。
Anon_

2019/03/11 04:38

アニメーション開始のときに.asの要素にアニメーション開始済を示すクラスを付与してアニメーション開始済の場合は処理をはしらせないようにしようと思いますが、対策としてあっていますでしょうか。
Lhankor_Mhy

2019/03/11 04:53

それもいいとおもうのですが、resizeイベントはまともに受けてしまうと負荷が高いので、↓のようにsetTimeoutかませるのがいいかと思います。 https://w3g.jp/blog/intermittent_event_load_reduce なお、「次の処理がはしってdeferredArrが空になる」というのは、コードを見る感じでは、なさそうかと思いますし、deferredArr が空の配列でもエラーは起きないんじゃないでしょうか?
Anon_

2019/03/11 08:25

とても参考になりました。 async/awaitについては理解を深めないとまだまだ使いこなせそうにありませんががんばりたいです。 ありがとうございました。
guest

回答2

0

resolveの発火タイミングがおかしいです。

$(this).delay(200).css("visibility","visible").animate({opacity: 1}, 1000);の部分が非同期処理であり、内部的にイベント登録だけして200m秒後に実行してねよろと言って逃げています。
(JavaScriptはシングルスレッドなのでスリープやらビジーループで止めるとブラウザの応答がなくなりプチフリする)
つまり、何の成約もなくポチっと動作させるresolveのほうが先に実行されてしまいます。

イベントループのタイミング的に200msの関数とどっちが先に実行するのかという話になりますが、
最近のJSは優秀なので200ms後ならPromiseのthenのほうが先に動作すると思います。
この辺は「イベントループ」で調べてみてください。


さて、実際の解決策

jQueryで、順番に実行が出来る .when() から .done() が便利だったのでメモ

この辺読みながら、doneの中でresolve叩けるように調整しましょう。
jQueryは実行を司るeachではなく、配列を生成するmap→getのルートがあり、Promiseの配列を作りたいならこちらを使うと良いでしょう。
Promiseの配列はPromise.allで全てresolve実行されたら完了するというpromiseに出来るので、やりたい事が実現出来ることでしょう。

投稿2019/03/11 00:47

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/03/11 01:17

jQueryなので、.animate()の配列を$.when.applyで受ける、という流れでもいいかもしれません。
Anon_

2019/03/11 02:16

なんとなく分かりかけているのですが、つまり私がやりたいことはPromiseやawait/asyncを使わずとも$.whenで実現できるという事でしょうか。
Anon_

2019/03/11 03:06

修正しましたがうまく動かないので確認していただけますでしょうか。
yambejp

2019/03/11 03:08

しつこいようですがHTMLの明記を
Anon_

2019/03/11 04:08

すみません、一部コードミスがありました。 今回はPromise.allを使用せずとも実現できましたが、機会があれば使ってみたいと思います。
guest

0

ベストアンサー

$(".as").each(...)は、アニメーションの実行開始であり、その後すぐにresolve();を実行していますから、Promiseの解決がアニメーション終了を意味しません。

幸いなことにjQuery.DeferredはPromise-compatibleで、awaitはダックタイピング的な振る舞いをしますので、Promiseを省略して$.when()に直接awaitを書くことができます。ただし、jQueryのバージョンに注意してください

こんな感じで動作するはずです。(動作未確認)

js

1 function promiseIncrement() { 2 var deferredArr = []; 3 $(".as").each(function(i){ 4 var imgPos = $(this).offset().top; 5 var scroll = $(window).scrollTop(); 6 var windowHeight = $(window).height(); 7 8 if (scroll > imgPos - windowHeight + windowHeight / 3){ 9 // ここに処理を書く 10 deferredArr.push( $(this).delay(200).css("visibility","visible").animate({opacity: 1}, 1000)); 11 } 12 } ); 13 return $.when( ...deferredArr ); 14 }

投稿2019/03/11 01:50

編集2019/03/11 03:08
Lhankor_Mhy

総合スコア35865

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Anon_

2019/03/11 02:07

whenの中でawaitが書けるとのことですが、提示いただいたコードですと、whenのなかで配列を回してその後、doneでつなげるという流れでしょうか?
Lhankor_Mhy

2019/03/11 02:20

「whenの中でawaitが書ける」ではなくて、 await $.when(); と書ける、ということです。 $.when は、引数にとった $.Deferred が全て終了するのを待って resolve する $.Deferred を返します。なのでこれは、 await $.Deferred(); と同様のことです。
Anon_

2019/03/11 03:06

修正しましたがうまく動かないので確認していただけますでしょうか。 また、ご提示いただいたコードに一部typoがありましたので一応お知らせしておきます。 deffeedArr.pushの箇所です。
Lhankor_Mhy

2019/03/11 03:08

おっと、失礼しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問