回答編集履歴
4
文章訂正
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
例を追加
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
コードミス
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に統一
answer
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
ところで普通の計算機のtimeoutの分解能はせいぜい10msecぐらいですので、実験するにしてもあまり短期間の非同期処理だと順番が乱れるかもしれません。下記の程度なら15, 10, 5にしても動くようでしたが。
|
12
12
|
|
13
13
|
```javascript
|
14
|
-
|
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定義に置き換えました。
|