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

回答編集履歴

7

最終更新

2018/04/11 08:59

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -32,8 +32,12 @@
32
32
  やっぱり使い方分かってないじゃないですか。
33
33
 
34
34
  まずコールバック引数というのは1つ以上の引数を必ず参照する作りにしてください。
35
- 中身でエラーが出てもtry~catchで取る事が出来ないので、第一引数はかならずerrになるからです。
35
+ 中身でエラーが出てもtry~catchで取る事が出来ないので、
36
+ 非同期処理を司るライブラリなんかは全て第一引数はかならずerrにするというルールがあるからです。
36
37
 
38
+ もし後続の処理を行われたらまずいという場合は、
39
+ `new Error('エラー理由')`でエラーを作成して第一引数に設定してください。
40
+
37
41
  そして第二引数以降に、コールバック関数が使いたいと考えている変数を全て引数としてぶち込んで下さい。
38
42
  これはnewObjをasyncCallbackで使えるようにした例です。
39
43
 
@@ -47,13 +51,15 @@
47
51
  }, 0);
48
52
  }
49
53
 
50
- // コールバック関数は必ず第一引数をerrにしてください。
54
+ // コールバック関数は必ず第一引数をerrにする
51
- // objとnewObjが使いたいと思ってそうでしたので両方要求する関数にしました。
55
+ // objとnewObjが使いたそうでしたので両方要求する関数に
52
56
  function asyncCallback (err, obj, newObj) {
53
57
  if (err) console.error(err);
58
+ // 本命の処理を行う
59
+ console.log(obj);
54
- console.log(err, newObj);
60
+ console.log(newObj);
55
61
  }
56
62
 
57
- const obj = {};
63
+ // objもnewObjもここで宣言しない方が良いので削除
58
- const newObj = makeNewObj(obj, asyncCallback);
64
+ makeNewObj({}, asyncCallback);
59
65
  ```

6

再調整

2018/04/11 08:59

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -31,22 +31,27 @@
31
31
  ああ、なるほど…
32
32
  やっぱり使い方分かってないじゃないですか。
33
33
 
34
- コールバック引数というのは1つ以上の引数を必ず参照する作りにしてください。
34
+ まずコールバック引数というのは1つ以上の引数を必ず参照する作りにしてください。
35
+ 中身でエラーが出てもtry~catchで取る事が出来ないので、第一引数はかならずerrになるからです。
35
36
 
37
+ そして第二引数以降に、コールバック関数が使いたいと考えている変数を全て引数としてぶち込んで下さい。
38
+ これはnewObjをasyncCallbackで使えるようにした例です。
39
+
36
40
  ```JavaScript
37
41
  function makeNewObj(obj, callback) {
38
42
  // いろいろな処理がこの辺に
39
43
  // 非同期コールバックを表現するためにsetTimeoutを利用
40
44
  setTimeout(function() {
41
45
  // コールバックに値を引き継ぎたいので関数適用時の引数として渡す
42
- callback(null, {new: true});
46
+ callback(null, obj, {new: true});
43
47
  }, 0);
44
48
  }
45
49
 
46
50
  // コールバック関数は必ず第一引数をerrにしてください。
47
- // if: もしobj使いたければ引数を3つ取る関数にする
51
+ // objとnewObjが使いたいと思ってそうでしたので両方要求する関数にしました。
48
- function asyncCallback (err, newObj) {
52
+ function asyncCallback (err, obj, newObj) {
53
+ if (err) console.error(err);
49
- console.log(err, newObj)
54
+ console.log(err, newObj);
50
55
  }
51
56
 
52
57
  const obj = {};

5

returnを削除出来て居なかったので再修正

2018/04/11 08:51

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -41,13 +41,12 @@
41
41
  // コールバックに値を引き継ぎたいので関数適用時の引数として渡す
42
42
  callback(null, {new: true});
43
43
  }, 0);
44
- // 新しいオブジェクトを返します。
45
- return {new: true};
46
44
  }
47
45
 
48
46
  // コールバック関数は必ず第一引数をerrにしてください。
47
+ // if: もしobjも使いたければ引数を3つ取る関数にする
49
- function asyncCallback (err, value) {
48
+ function asyncCallback (err, newObj) {
50
- console.log(err, value)
49
+ console.log(err, newObj)
51
50
  }
52
51
 
53
52
  const obj = {};

4

全面的に書き直し

2018/04/11 08:41

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -1,83 +1,55 @@
1
- もそも、質問それはコールバック関数を適用出来ません。
1
+ > 以下はのコードを質問用に簡略化したコードなですが、関数式の代入先オブジェクトを関数に渡すコールバック関数の中で参照出来るのは、どうう仕組みからなのでしょうか?(質問1)
2
2
 
3
- ```JavaScript
4
- function otherLibrary (callback) {
5
- // 非同期コールバック
3
+ コールバック関数適用と戻り値は完全に異なるものです。
6
- // ネットワークやI/O通信が終わり次第、イベントループに設定されて下記のコードが実行される
7
- // まぁ今回は横着してコンマ0秒通信完了したにしprocess.nextTick利用
4
+ 非同期処理コールバック関数を渡したからいっ、戻り値返してはならないというルールは存在しません。
8
- process.nextTick(() => callback(err, value));
9
- }
10
5
 
11
- function makeNewObj(obj, callback) {
6
+ setTimeoutなんかはこの両者の違いを上手に使っている典型例の一つで、
12
- // いろいろな処理がこの辺
7
+ 一度コールバック関数で遅延させると同時、IDが戻り値として返ってきます。
13
- otherLibrary(callback);
8
+ やっぱり実行を辞めたい場合はキャンセル関数に渡して上げる事で実行を取り下げる事が可能です。
14
9
 
10
+ ```JavaScript
11
+ var id = setTimeout(() => console.log('test'), 10000);
15
- // こいつオブジェクト
12
+ // 異常を感じたのでやっぱりキャンセルだ!
16
- return {new: true};
13
+ clearTimeout(id);
17
- }
18
-
19
- function asyncCallback (err, value) {
20
- // err, valueはこの関数内でアクセスすることになる
21
- console.log(err, value);
22
- }
23
-
24
- const newObj = makeNewObj(obj, asyncCallback);
25
- // これはあくまでmakeNewObjectの戻り値
26
- // errやvalueにはどう足掻いてもどり着けない
14
+ // test <- キャンセルされので文字は表示されない
27
- // { new: true }
28
15
  ```
29
16
 
30
- こんな関係になっています。
31
- て、ライブラリでは「は実行しおくよまま次行ってね」と通信を開始るだけです
17
+ > とりあえず僕的にはこういうことが可能らしいということはわかのですが、直感的でと感じていて、これは良い作法なかどうかも気なります。(質問2)
32
18
 
33
- ので、上記のerrやvalueを同期的なコードで受け取る事は絶対不可能で
19
+ setTimeoutように意味があれば良い作法ですし、
34
- (ES2017のasync / awaitを活用すれば見てくれだけは同期的に出来ますけどね)
20
+ 意味が無ければ辞めたほうが良いでしょう。
35
21
 
22
+ [UNIX哲学](https://ja.wikipedia.org/wiki/UNIX%E5%93%B2%E5%AD%A6)に「一つのことを行い、またそれをうまくやるプログラムを書け。」とあります。
36
- ---
23
+ あまり色々な機能をゴテゴテと付け足した関数は汎用性が失われ使い勝手が悪くなります。
37
24
 
25
+ これらの事から、setTimeoutのようにキャンセルすることを見越してキー情報を返す。
38
- コールバック関数とは、子供のお使いみたいなものです
26
+ …くらいの使い方以外はすることなんじゃですかね?
39
- では、朝子供が学校にいったママの行動を例としながら説明していきましょう。
40
27
 
41
- まず朝子供に朝食を食べさせ学校に向かわせます。
42
- ここまで子供は自宅に居るのでコントロール可能です(同期処理)
43
- ママ子供を学校送る関数叩き子供は自分手元を離れて学校へ移動はじめました
28
+ > もし、これが良い作法でない場合、このようコールバックの中で代入先参照したいような場合にような方法が取るのかを教え頂けると嬉いです(質問3)
44
29
 
30
+ ???
31
+ ああ、なるほど…
45
- 子供が学校に行っている間に、ママは書き置きを作ります。
32
+ ぱり使い方分かっじゃないで
46
- 「学校から帰ってきたら、プリントを机に出す、手を洗う、冷蔵庫のプリンを食べる」
47
33
 
48
- 子供が学校から返ってきたら、その書き置きを読み、
49
- 自発的にプリント机に出し、手を洗って、冷蔵庫プリン始めます
34
+ コールバック引数というは1つ以上の引数必ず参照する作てください
50
35
 
51
- この書き置きがJavaScriptにおけるコールバック関数なのです。
52
- 子供が学校に行っている間、ママは学校で何があったかを把握することが出来ません。
53
- なので、学校へ送り出す関数の戻り値で、先生が渡したプリントを取得することは出来ません。
54
-
55
- このイメージをコードにあらわしてみました。
56
-
57
36
  ```JavaScript
58
- function toSchool (child, kakioki) {
37
+ function makeNewObj(obj, callback) {
38
+ // いろいろな処理がこの辺に
39
+ // 非同期コールバックを表現するためにsetTimeoutを利用
59
- setTimeout(function () {
40
+ setTimeout(function() {
60
- var print = '今日学級通信';
41
+ // コールバックに値を引き継ぎたいで関数適用時の引数として渡す
61
- kakioki(null, print);
42
+ callback(null, {new: true});
43
+ }, 0);
44
+ // 新しいオブジェクトを返します。
62
- }, 8 * 60 * 60 * 1000);
45
+ return {new: true};
63
- return child + 'が登校しました';
64
46
  }
65
47
 
66
- var child = '太郎';
67
- var result = toSchool(child, function (err, print) {
68
- // 慣習としてコールバック関数第一引数はエラー
48
+ // コールバック関数は必ず第一引数をerrにしてください。
69
- if (err) {
70
- // 異常あり!子供が返ってこない!?電話する等の対応
49
+ function asyncCallback (err, value) {
71
- throw err;
50
+ console.log(err, value)
72
- }
51
+ }
73
52
 
74
- // 以降は書き置きの内容
75
- console.log('プリントを机の上に出す');
76
- console.log(print); // 今日の学級通信
77
- console.log('手洗い');
78
- console.log('冷蔵庫のプリンを食べる');
79
- });
80
-
81
- console.log(result);
53
+ const obj = {};
82
- // 太郎が登校しました
54
+ const newObj = makeNewObj(obj, asyncCallback);
83
55
  ```

3

コードをもうちょっと洗練

2018/04/11 08:38

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -63,15 +63,21 @@
63
63
  return child + 'が登校しました';
64
64
  }
65
65
 
66
+ var child = '太郎';
67
+ var result = toSchool(child, function (err, print) {
66
- // 約8時間経った後に実行
68
+ // 慣習としてコールバック関数の第一引数はエラー
67
- function kakioki (err, print) {
69
+ if (err) {
68
- if (err) throw err; // 異常あり!子供が返ってこない!?電話する等の対応
70
+ // 異常あり!子供が返ってこない!?電話する等の対応
69
- console.log(print);
71
+ throw err;
70
- // 今日の学級通信
71
- }
72
+ }
72
73
 
74
+ // 以降は書き置きの内容
75
+ console.log('プリントを机の上に出す');
76
+ console.log(print); // 今日の学級通信
73
- var child = '太郎';
77
+ console.log('手洗い');
74
- var result = toSchool(child, kakioki);
78
+ console.log('冷蔵庫のプリンを食べる');
79
+ });
80
+
75
81
  console.log(result);
76
82
  // 太郎が登校しました
77
83
  ```

2

関係をもう少し詳しく

2018/04/11 08:24

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -50,4 +50,28 @@
50
50
 
51
51
  この書き置きがJavaScriptにおけるコールバック関数なのです。
52
52
  子供が学校に行っている間、ママは学校で何があったかを把握することが出来ません。
53
- なので、学校へ送り出す関数の戻り値で、先生が渡したプリントを取得することは出来ません。
53
+ なので、学校へ送り出す関数の戻り値で、先生が渡したプリントを取得することは出来ません。
54
+
55
+ このイメージをコードにあらわしてみました。
56
+
57
+ ```JavaScript
58
+ function toSchool (child, kakioki) {
59
+ setTimeout(function () {
60
+ var print = '今日の学級通信';
61
+ kakioki(null, print);
62
+ }, 8 * 60 * 60 * 1000);
63
+ return child + 'が登校しました';
64
+ }
65
+
66
+ // 約8時間経った後に実行
67
+ function kakioki (err, print) {
68
+ if (err) throw err; // 異常あり!子供が返ってこない!?電話する等の対応
69
+ console.log(print);
70
+ // 今日の学級通信
71
+ }
72
+
73
+ var child = '太郎';
74
+ var result = toSchool(child, kakioki);
75
+ console.log(result);
76
+ // 太郎が登校しました
77
+ ```

1

process.nextTickを追加

2018/04/11 08:20

投稿

miyabi-sun
miyabi-sun

スコア21482

answer CHANGED
@@ -4,7 +4,8 @@
4
4
  function otherLibrary (callback) {
5
5
  // 非同期コールバック
6
6
  // ネットワークやI/O通信が終わり次第、イベントループに設定されて下記のコードが実行される
7
+ // まぁ今回は横着してコンマ0秒で通信完了したことにしてprocess.nextTickを利用
7
- callback(err, value);
8
+ process.nextTick(() => callback(err, value));
8
9
  }
9
10
 
10
11
  function makeNewObj(obj, callback) {