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

回答編集履歴

4

文章訂正

2018/04/18 04:09

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -39,7 +39,7 @@
39
39
  追記:短く書くためにES2015で書いてます。最初の回答で`var f = (to) => {...}`としましたが特に意図あってのことではなかったのでfを普通のfunction定義に置き換えました。
40
40
 
41
41
  ---
42
- 追記: Javascriptで書いた部分は(Workerを使って意識的に非同期なスレッドで行わない限り)必ず同期的に行われます。Promiseは**非同期に何かをしてくれる機構ではなく**、非同期に行われる処理が完了してから次のことをするための**同期機構にしか過ぎない**ということがわかぁと思いま
42
+ 追記: Javascriptで書いた部分は(Workerを使って意識的に非同期なスレッドで行わない限り)必ず同期的に行われます。Promiseは**非同期に何かをしてくれる機構ではなく**、非同期に行われる処理が完了してから次のことをするための**同期機構にしか過ぎない**ということが伺えよう例を書てみした
43
43
 
44
44
  ```javascript
45
45
  const t0 = +new Date()

3

例を追加

2018/04/18 04:09

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -36,4 +36,109 @@
36
36
  150
37
37
 
38
38
  ---
39
- 追記:短く書くためにES2015で書いてます。最初の回答で`var f = (to) => {...}`としましたが特に意図あってのことではなかったのでfを普通のfunction定義に置き換えました。
39
+ 追記:短く書くためにES2015で書いてます。最初の回答で`var f = (to) => {...}`としましたが特に意図あってのことではなかったのでfを普通のfunction定義に置き換えました。
40
+
41
+ ---
42
+ 追記: Javascriptで書いた部分は(Workerを使って意識的に非同期なスレッドで行わない限り)必ず同期的に行われます。Promiseは**非同期に何かをしてくれる機構ではなく**、非同期に行われる処理が完了してから次のことをするための**同期機構にしか過ぎない**ということがわかるかなぁと思います。
43
+
44
+ ```javascript
45
+ const t0 = +new Date()
46
+
47
+ function log(msg) {
48
+ const elapsed = " " + (+new Date() - t0)
49
+ const prefix = elapsed.slice(elapsed.length - 4)
50
+ console.log(`${prefix}: ${msg}`)
51
+ }
52
+
53
+ function f(msg, sy, to) {
54
+ log(`invoked ${msg}(${sy} ${to})`)
55
+ return new Promise((resolve, reject) => {
56
+ if (sy == 'sync') {
57
+ const start = +new Date()
58
+ do {} while (+new Date() - start <= to)
59
+ doResolve()
60
+ } else {
61
+ setTimeout(() => doResolve(), to)
62
+ }
63
+
64
+ function doResolve() {
65
+ resolve(`${msg} ${sy} ${to}`)
66
+ log(`resolved ${msg} ${sy} ${to}`)
67
+ }
68
+ })
69
+
70
+ }
71
+
72
+ function done(r) {
73
+ log(`promise chain done ${r}`)
74
+ }
75
+
76
+ f('A', 'async', 0).then(r => f(`${r}->then`, 'async', 0)).then(done)
77
+ f('B', 'async', 0).then(r => f(`${r}->then`, 'async', 0)).then(done)
78
+ f('C', 'async', 100).then(r => f(`${r}->then`, 'async', 200)).then(done)
79
+ f('D', 'async', 200).then(r => f(`${r}->then`, 'async', 100)).then(done)
80
+ f('--', 'async', 1000)
81
+ .then(r => {
82
+ f('A', 'sync', 0).then(r => f(`${r}->then`, 'sync', 0)).then(done)
83
+ f('B', 'sync', 0).then(r => f(`${r}->then`, 'sync', 0)).then(done)
84
+ f('C', 'sync', 100).then(r => f(`${r}->then`, 'sync', 200)).then(done)
85
+ f('D', 'sync', 200).then(r => f(`${r}->then`, 'sync', 100)).then(done)
86
+ })
87
+ ```
88
+ 結果
89
+ ```text
90
+ 1: invoked A(async 0)
91
+ 2: invoked B(async 0)
92
+ 2: invoked C(async 100)
93
+ 2: invoked D(async 200)
94
+ <--本来の非同期処理の場合、非同期処理の起動は一気に行われる
95
+ 2: invoked --(async 1000)
96
+ 2: resolved A async 0
97
+ 2: resolved B async 0
98
+ 2: invoked A async 0->then(async 0)
99
+ 2: invoked B async 0->then(async 0)
100
+ 2: resolved A async 0->then async 0
101
+ 2: resolved B async 0->then async 0
102
+ 2: promise chain done A async 0->then async 0
103
+ 2: promise chain done B async 0->then async 0
104
+ <--C/Dなど時間がかかる処理があってもそれを非同期に行いさえすればA/BはC/Dの完了前に完了する
105
+ <--これはPromiseによる恩恵ではない。A/B/C/Dの処理(setTimeout)が非同期であることがポイント
106
+ 112: resolved C async 100
107
+ 112: invoked C async 100->then(async 200)
108
+ 206: resolved D async 200
109
+ 206: invoked D async 200->then(async 100)
110
+ 315: resolved D async 200->then async 100
111
+ 315: promise chain done D async 200->then async 100
112
+ 315: resolved C async 100->then async 200
113
+ 315: promise chain done C async 100->then async 200
114
+ 1008: resolved -- async 1000
115
+ 1008: invoked A(sync 0)
116
+ 1024: resolved A sync 0
117
+ 1024: invoked B(sync 0)
118
+ 1039: resolved B sync 0
119
+ 1039: invoked C(sync 100)
120
+ 1149: resolved C sync 100
121
+ 1149: invoked D(sync 200)
122
+ <-- Cは同期的に(ビジーループで)100ms消費するためDはその後に起動される(全然非同期でない)
123
+ 1359: resolved D sync 200
124
+ 1359: invoked A sync 0->then(sync 0)
125
+ <-- C,Dが同期的に300ms処理しているためAがとっくに終わっていても
126
+ A/Bのthen部分はC/Dの起動後にしか動けない
127
+ 1375: resolved A sync 0->then sync 0
128
+ 1375: invoked B sync 0->then(sync 0)
129
+ 1391: resolved B sync 0->then sync 0
130
+ 1391: invoked C sync 100->then(sync 200)
131
+ 1594: resolved C sync 100->then sync 200
132
+ 1594: invoked D sync 200->then(sync 100)
133
+ <-- Dのthen部分は1359ms後にresolveされている。しかしCのthen部分を同期的に処理しているため
134
+ それが終わらないとDのthen部分が起動できない
135
+ Dのthen部分はresolveされてから250msも後になってからでないと起動されない(全然非同期でない)
136
+ 1703: resolved D sync 200->then sync 100
137
+ 1703: promise chain done A sync 0->then sync 0
138
+ 1703: promise chain done B sync 0->then sync 0
139
+ 1703: promise chain done C sync 100->then sync 200
140
+ 1703: promise chain done D sync 200->then sync 100
141
+ <-- 肝心の処理が同期的になっているとPromiseを使ってもなんら意味がない
142
+ A-Bの処理が全て終わってからでないとpromise chainが完了しないことからもそれがわかる
143
+ ```
144
+ Javascriptで記述するのは「非同期処理を起動するのに必要なパラメーター計算と非同期処理の起動」「非同期処理が完了した際に結果を料理すること」であり、どちらも一瞬で終わるべき処理内容とするのが普通だと思います。それは基本的に非同期APIを用いて論理を書くからです。もし同期APIを用いて逐次的に処理するような機能を並行して動かしたいのならthink49さんが回答しておられるようにWorkerのようなマルチスレッド機構を用いることになると思います。

2

コードミス

2018/04/18 04:07

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -11,7 +11,7 @@
11
11
  ところで普通の計算機のtimeoutの分解能はせいぜい10msecぐらいですので、実験するにしてもあまり短期間の非同期処理だと順番が乱れるかもしれません。下記の程度なら15, 10, 5にしても動くようでしたが。
12
12
 
13
13
  ```javascript
14
- function f(to) => {
14
+ function f(to) {
15
15
  return new Promise((resolve, reject) => {
16
16
  setTimeout(() => resolve(to), to)
17
17
  })

1

ES2015に統一

2018/04/17 10:54

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -11,7 +11,7 @@
11
11
  ところで普通の計算機のtimeoutの分解能はせいぜい10msecぐらいですので、実験するにしてもあまり短期間の非同期処理だと順番が乱れるかもしれません。下記の程度なら15, 10, 5にしても動くようでしたが。
12
12
 
13
13
  ```javascript
14
- var f = (to) => {
14
+ function f(to) => {
15
15
  return new Promise((resolve, reject) => {
16
16
  setTimeout(() => resolve(to), to)
17
17
  })
@@ -33,4 +33,7 @@
33
33
  150
34
34
  50
35
35
  100
36
- 150
36
+ 150
37
+
38
+ ---
39
+ 追記:短く書くためにES2015で書いてます。最初の回答で`var f = (to) => {...}`としましたが特に意図あってのことではなかったのでfを普通のfunction定義に置き換えました。