95584


JavaScriptの非同期処理についての質問です。

技術書や各々の解説ブログでは「コールバック関数は非同期処理」であると書かれています。  
そこで以下のコードを実行してみたところ、自分のイメージしていた通りの結果になりませんでした。

[code]

    function a(callback) {
      console.log('a');
      callback();
      console.log('finish');
    }
    
    function b() {
      for(let i = 0; i <= 100; i++) {
        console.log(i);
      }
    }
    
    a(b);
    
[/code]

関数aの中で関数bを呼び出しています。  
この場合、関数bはコールバック関数なので、非同期処理になるというのが  
今の自分の理解です。

そのため関数bの処理が完了するのを待たずに

[code]

    console.log('finish');
    
[/code]

が実行されるものと考えていました。

■想像していたconsoleの結果

> a  
>  finish  
>  1  
>  2  
>  ...  
>  100

■実際のconsoleの結果

> a  
>  1  
>  2  
>  ...  
>  100  
>  finish

関数bがコールバック関数で非同期に処理されるなら  
bの処理の完了を待たず後続の

[code]

    console.log('finish');
    
[/code]

が処理されると思っていましたがそうではありませんでした。

自分の理解がどこか間違っていると思うのですが、それがわかりません。

どなたか、JavaScript初心者にコールバック関数と非同期処理について  
ご教示いただけますと幸いです。


CC BY-SA 4.0
2023-07-13T00:54:09.193
95580
2023-07-13T05:38:41.147
34060
question
javascript 非同期
JavaScriptではコールバック関数はすべて非同期処理になるのか？


コールバック関数が必ず非同期に呼ばれるということはありません。その関数 `a()`
は同期的にコールバック関数を呼んでいるので非同期ではありません。同期か非同期かはコールバック関数を受け取る関数の仕様次第です。

非同期に起きる何かに反応して関数を呼びたいなら非同期にコールバック関数を呼ぶでしょうし、内部動作のカスタマイズをする目的なら同期でコールバック関数を呼ぶことが多いでしょう。`addEventListener()`
`Promise` は前者、`forEach()` `filter()` は後者の例になります。


CC BY-SA 4.0
2023-07-13T01:19:14.187
95581
2023-07-13T05:24:28.367
2023-07-13T05:24:28.367
3475
3475
95580
answer


> 技術書や各々の解説ブログでは「コールバック関数は非同期処理」であると書かれています。

どこにどのように書いてあったのか分かりませんが、誤解があるのではと思います。

質問のコードは 100% 同期です (function a に書いた順番に上から下に実行される)。たとえ、function b の中で setTimeout
を使って待つようなことをしても、function a では callback(); の完了を待って console.log('finish');
が実行されます。

function b を非同期にしたいということであれば、プロミスベースのメソッドにしてはいかがですか？

例えば以下のような感じです。

[code]

    function a(callback) {
        console.log('a');
        callback();
        console.log('finish');
    }
    
    // a が b を呼ぶと、b は Promise オブジェクトを生成して即座に戻り値として返す。
    
    // Promise コンストラクタの引数の executor 関数（下のコード例では (resolve) => { ... } 
    // が該当）は new Promise の時点で自動的かつ即座に実行される。
    
    // executor 関数内の setTimeout により 2 秒後に for ループが動いてコンソールに出力される
    
    function b() {
        return new Promise((resolve) => {
            setTimeout(() => {
                for (let i = 0; i <= 5; i++) {
                    console.log(i);
                }
                // function a で callback(); を await する場合はこれを呼び出さないと
                // 止まってしまうので注意
                resolve();
            }, 2000)
        });
    }
    
    a(b);
    
[/code]

結果は:

[![画像の説明をここに入力](https://i.stack.imgur.com/20oIY.jpg)](https://i.stack.imgur.com/20oIY.jpg)


CC BY-SA 4.0
2023-07-13T04:09:58.647
95584
2023-07-13T05:38:41.147
2023-07-13T05:38:41.147
51338
51338
95580
answer