teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

9

テキスト修正

2019/10/12 19:52

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -79,7 +79,7 @@
79
79
  ### 3. 最後の文字まで表示するのを一つのPromiseにする。
80
80
 
81
81
 
82
- 上記の 1. と 2. とは異なり、「200ミリ秒間隔でひと文字ずつ、最後の文字まで表示する」という処理をひとつの Promise にすることもできます。この場合は Promise.all は使わず、以下のようになります。
82
+ 上記の 1. と 2. とは異なり、「200ミリ秒間隔でひと文字ずつ、最後の文字まで表示する」という処理をひとつの Promise にすることもできます。以下のそのコード例です。
83
83
  ```javascript
84
84
  const addTypingMovement = (word, target) => new Promise(
85
85
  resolve => {
@@ -106,9 +106,12 @@
106
106
  finishTitleCall(message);
107
107
  })();
108
108
  ```
109
- また上記では `Done.`という文字列を `resolve`の引数で返させました。
109
+    
110
-
111
110
  - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/14/](https://jsfiddle.net/jun68ykt/bcm7jgzw/14/)
112
111
 
112
+ 上記では、
113
+ - `setTimeout`の替わりに`setInterval`を使っています。
114
+ - 文字列全体が表示されるまでをひとつの Promise にするので、 `Promise.all` は使わなくなっています。
115
+ - `Done.`という文字列を `resolve`の引数で返させるようにしました。
113
116
 
114
117
  以上、参考になれば幸いです。

8

テキスト修正

2019/10/12 19:52

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -79,24 +79,23 @@
79
79
  ### 3. 最後の文字まで表示するのを一つのPromiseにする。
80
80
 
81
81
 
82
- 上記の 1. と 2. とは異なり、「200ミリ秒間隔で文字を追加するのを、最後の文字まで行う」という処理をひとつの Promise にすることもできます。この場合は Promise.all は使わず、以下のようになります。
82
+ 上記の 1. と 2. とは異なり、「200ミリ秒間隔でひと文字ずつ、最後の文字まで表示する」という処理をひとつの Promise にすることもできます。この場合は Promise.all は使わず、以下のようになります。
83
83
  ```javascript
84
- const addTypingMovement = (word, target) => {
84
+ const addTypingMovement = (word, target) => new Promise(
85
- const wordArray = [...word];
85
+ resolve => {
86
- const printTarget = document.querySelector(target);
86
+ const printTarget = document.querySelector(target);
87
-
88
- return new Promise(resolve => {
87
+ let i = 0;
89
88
  const intervalId = setInterval(
90
89
  () => {
91
- if (wordArray.length > 0) {
90
+ if (i < word.length) {
92
- printTarget.textContent += wordArray.shift();
91
+ printTarget.textContent = word.substring(0, ++ i);
93
92
  } else {
94
93
  clearInterval(intervalId);
95
94
  resolve('Done.');
96
95
  }
97
96
  }, 200);
98
- });
99
- }
97
+ }
98
+ );
100
99
 
101
100
  const finishTitleCall = (message) => {
102
101
  document.querySelector('#result').textContent = message;
@@ -109,7 +108,7 @@
109
108
  ```
110
109
  また上記では `Done.`という文字列を `resolve`の引数で返させました。
111
110
 
112
- - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/5/](https://jsfiddle.net/jun68ykt/bcm7jgzw/5/)
111
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/14/](https://jsfiddle.net/jun68ykt/bcm7jgzw/14/)
113
112
 
114
113
 
115
114
  以上、参考になれば幸いです。

7

テキスト修正

2019/10/12 19:42

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -86,7 +86,6 @@
86
86
  const printTarget = document.querySelector(target);
87
87
 
88
88
  return new Promise(resolve => {
89
- let i = 0;
90
89
  const intervalId = setInterval(
91
90
  () => {
92
91
  if (wordArray.length > 0) {
@@ -110,7 +109,7 @@
110
109
  ```
111
110
  また上記では `Done.`という文字列を `resolve`の引数で返させました。
112
111
 
113
- - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/4/](https://jsfiddle.net/jun68ykt/bcm7jgzw/4/)
112
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/5/](https://jsfiddle.net/jun68ykt/bcm7jgzw/5/)
114
113
 
115
114
 
116
115
  以上、参考になれば幸いです。

6

テキスト修正

2019/10/12 18:32

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -1,5 +1,14 @@
1
1
  こんにちは
2
2
 
3
+ この回答では3つのコードを挙げます。ご質問のタイトルに、
4
+
5
+ > for文内にsetTimeoutがある関数に対して、・・・
6
+
7
+
8
+ とあったので、 まずご質問のコードにある forループを生かしたコードを回答します。その後、for文を使わないコードを2つ挙げます。
9
+
10
+ ### 1. forループで、各文字を追加するPromiseの配列を作る。
11
+
3
12
  各文字を追加していく処理をひとつのPromiseにして、それらがすべてresolve されたら、Doneを表示するという前後関係を担保するために、 [Promise.all](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) を使えばよいかと思います。
4
13
 
5
14
  以下、ご質問に挙げられているコードに、上記の趣旨の追加をしたものです。
@@ -34,8 +43,11 @@
34
43
 
35
44
  - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/6/](https://jsfiddle.net/jun68ykt/6wsp3onu/6/)
36
45
 
37
- 上記のコードで、Promiseの配列を作るところの for文を [map](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map) を使って書き換え、 すべての文字が `target` に追加されたら、Done を表示するために `async`, `await` を使った例が以下です。
38
46
 
47
+ ### 2. forの替わりにmapを、前後関係の制御にasync/awaitを使用
48
+
49
+ 上記 1. のコードで、Promiseの配列を作るところの for文を [map](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map) を使って書き換え、 すべての文字が `target` に追加されたら、Done を表示するために `async`, `await` を使った例が以下です。
50
+
39
51
  ```javascript
40
52
  const addTypingMovement = (word, target) => {
41
53
 
@@ -64,11 +76,10 @@
64
76
  ```
65
77
  - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/25/](https://jsfiddle.net/jun68ykt/6wsp3onu/25/)
66
78
 
67
- 以上、参考になれば幸いです。
79
+ ### 3. 最後の文字ま表示るのを一つのPromiseにする
68
80
 
69
- ### 追記
70
81
 
71
- やり方して、「200ミリ秒間隔で各文字を追加するのを、最後の文字まで行う」という処理をひとつの Promise にする方法あります。この場合は Promise.all は使わず、以下のようになります。
82
+ 上記 1. 2. とは異なり、「200ミリ秒間隔で各文字を追加するのを、最後の文字まで行う」という処理をひとつの Promise にすることできます。この場合は Promise.all は使わず、以下のようになります。
72
83
  ```javascript
73
84
  const addTypingMovement = (word, target) => {
74
85
  const wordArray = [...word];
@@ -99,4 +110,7 @@
99
110
  ```
100
111
  また上記では `Done.`という文字列を `resolve`の引数で返させました。
101
112
 
102
- - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/4/](https://jsfiddle.net/jun68ykt/bcm7jgzw/4/)
113
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/4/](https://jsfiddle.net/jun68ykt/bcm7jgzw/4/)
114
+
115
+
116
+ 以上、参考になれば幸いです。

5

テキスト修正

2019/10/12 18:23

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -78,11 +78,12 @@
78
78
  let i = 0;
79
79
  const intervalId = setInterval(
80
80
  () => {
81
+ if (wordArray.length > 0) {
81
- printTarget.textContent += wordArray[i ++];
82
+ printTarget.textContent += wordArray.shift();
82
- if (i === wordArray.length) {
83
+ } else {
83
84
  clearInterval(intervalId);
84
- resolve('Done.');
85
+ resolve('Done.');
85
- }
86
+ }
86
87
  }, 200);
87
88
  });
88
89
  }
@@ -96,6 +97,6 @@
96
97
  finishTitleCall(message);
97
98
  })();
98
99
  ```
99
- 上記では `Done.`という文字列を `resolve`の引数で返させました。
100
+ また上記では `Done.`という文字列を `resolve`の引数で返させました。
100
101
 
101
- - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/08axgkho/16/](https://jsfiddle.net/jun68ykt/08axgkho/16/)
102
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/bcm7jgzw/4/](https://jsfiddle.net/jun68ykt/bcm7jgzw/4/)

4

テキスト修正

2019/10/12 18:08

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -96,6 +96,6 @@
96
96
  finishTitleCall(message);
97
97
  })();
98
98
  ```
99
- 上記では `Done.`という文字列を `resole`の引数で返させました。
99
+ 上記では `Done.`という文字列を `resolve`の引数で返させました。
100
100
 
101
101
  - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/08axgkho/16/](https://jsfiddle.net/jun68ykt/08axgkho/16/)

3

テキスト修正

2019/10/12 17:52

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -64,4 +64,38 @@
64
64
  ```
65
65
  - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/25/](https://jsfiddle.net/jun68ykt/6wsp3onu/25/)
66
66
 
67
- 以上、参考になれば幸いです。
67
+ 以上、参考になれば幸いです。
68
+
69
+ ### 追記
70
+
71
+ 別のやり方として、「200ミリ秒間隔で各文字を追加するのを、最後の文字まで行う」という処理をひとつの Promise にする方法もあります。この場合は Promise.all は使わず、以下のようになります。
72
+ ```javascript
73
+ const addTypingMovement = (word, target) => {
74
+ const wordArray = [...word];
75
+ const printTarget = document.querySelector(target);
76
+
77
+ return new Promise(resolve => {
78
+ let i = 0;
79
+ const intervalId = setInterval(
80
+ () => {
81
+ printTarget.textContent += wordArray[i ++];
82
+ if (i === wordArray.length) {
83
+ clearInterval(intervalId);
84
+ resolve('Done.');
85
+ }
86
+ }, 200);
87
+ });
88
+ }
89
+
90
+ const finishTitleCall = (message) => {
91
+ document.querySelector('#result').textContent = message;
92
+ }
93
+
94
+ (async () => {
95
+ const message = await addTypingMovement('Hello World.', '#typing');
96
+ finishTitleCall(message);
97
+ })();
98
+ ```
99
+ 上記では `Done.`という文字列を `resole`の引数で返させました。
100
+
101
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/08axgkho/16/](https://jsfiddle.net/jun68ykt/08axgkho/16/)

2

テキスト修正

2019/10/12 17:44

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -62,6 +62,6 @@
62
62
  })();
63
63
 
64
64
  ```
65
- - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/24/](https://jsfiddle.net/jun68ykt/6wsp3onu/24/)
65
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/25/](https://jsfiddle.net/jun68ykt/6wsp3onu/25/)
66
66
 
67
67
  以上、参考になれば幸いです。

1

テキスト修正

2019/10/12 17:18

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -32,4 +32,36 @@
32
32
 
33
33
  以下は、ご質問に挙げられている jsFiddle をFork して、上記の修正版にしたものです。
34
34
 
35
- - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/6/](https://jsfiddle.net/jun68ykt/6wsp3onu/6/)
35
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/6/](https://jsfiddle.net/jun68ykt/6wsp3onu/6/)
36
+
37
+ 上記のコードで、Promiseの配列を作るところの for文を [map](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map) を使って書き換え、 すべての文字が `target` に追加されたら、Done を表示するために `async`, `await` を使った例が以下です。
38
+
39
+ ```javascript
40
+ const addTypingMovement = (word, target) => {
41
+
42
+ const printTarget = document.querySelector(target);
43
+
44
+ return [...word].map((char, i) => new Promise(
45
+ resolve => {
46
+ setTimeout(() => {
47
+ printTarget.textContent += char;
48
+ resolve();
49
+ }, i * 200);
50
+ })
51
+ );
52
+
53
+ }
54
+
55
+ const finishTitleCall = () => {
56
+ document.querySelector('#result').textContent = 'Done.';
57
+ }
58
+
59
+ (async () => {
60
+ await Promise.all(addTypingMovement('Hello World.', '#typing'));
61
+ finishTitleCall();
62
+ })();
63
+
64
+ ```
65
+ - **動作確認用 jsFiddle:** [https://jsfiddle.net/jun68ykt/6wsp3onu/24/](https://jsfiddle.net/jun68ykt/6wsp3onu/24/)
66
+
67
+ 以上、参考になれば幸いです。