質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.40%

  • JavaScript

    21451questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • 非同期処理

    143questions

    非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

【Promise,callback】どちらが良いのか?

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 958

OOO_777

score 40

 前提・実現したいこと

設定パターン1~2のコードがありますが、1はコールバック、2はプロミスで書いています。この場合どちらで書くべきでしょうか。
コールバックでも問題ないのか、それともプロミスで書いたほうが良いのか教えて頂ければ幸いです。

 該当のソースコード

//設定 パターン1
const ChangePermission = (callback) => {
  if('permissions' in navigator) {
    navigator.permissions.query({name:'notifications'}).then((notificationPerm) => {
      notificationPerm.onchange = () => {
        if(notificationPerm.state === "granted"){
          console.debug('通知が許可に変更');
          callback();
        }
      };
    });
  }
};
//設定 パターン2
const ChangePermission = () => {
  return new Promise((resolve, reject) => {
    if('permissions' in navigator) {
      navigator.permissions.query({name:'notifications'}).then((notificationPerm) => {
        notificationPerm.onchange = () => {
          if(notificationPerm.state === "granted"){
            console.debug('通知が許可に変更');
            resolve();
          }
        };
      });
    }
  });
};
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+5

Promiseを使うことのメリット・デメリットは、以下のような感じだと考えています。

  • メリット:resolverejectという2つの状態を持てる、async-awaitを使ってすっきり書くこともできる、Promise.allPromise.raceなどで並列実行の管理も容易、自動で非同期になる
  • デメリット:IE 11などではPolyfillが必要、コールバックを同期実行することができない

今回の場合は、自分だったらPromiseで書いて、拒否された時にもきちんとrejectしておく、というようなコードを書くと思います(ブラウザ通知はIE 11にないので、そこは気にしなくても構わない場面ですし)。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/16 12:19

    ご回答ありがとうございます。
    Promiseでのメリット、デメリット勉強になりました。
    ありがとうございます。

    キャンセル

+4

ぶっちゃけどっちでもいいです。
既存のライブラリや既存コードに合わせて統一するのが楽です。
callbackとpromiseの併用は寿命を縮めます。

promiseは配列の要素数分の非同期処理のループを作りたい、
みたいな状況でネストを発生させずに綺麗に書きやすい程度のメリットしかありません。
npmのasyncパッケージ等を上手く活用すればいつものコールバックで十分頑張れますからね。


そもそも1の書き方は駄目です。
コールバックを使う場合、第一引数はerrにしましょう。
(JSの非同期の処理はtry〜catchで補足出来ないので、第一引数をerrとして確実に分かるようにすべきという慣習があります)

const ChangePermission = (callback) => {
  // ガード節で抜けた方がネストが浅くなる + callbackの第一引数にerrを入れながら返す
  if(!('permissions' in navigator)) {
    callback(new Error('permissions is not in navigator.'));
  }
  navigator
    .permissions
    .query({name:'notifications'})
    .then((notificationPerm) => {
      notificationPerm.onchange = () => {
        if(notificationPerm.state !== "granted") return;
        console.debug('通知が許可に変更');
        callback(null);
      };
    })
    .catch(callback);
  }
};

質問文の例は終わり方が多いので、様々な状況に考慮する場合コードが増える傾向にあります。


promiseを使いつつ、ES2017で追加されたasync / awaitを利用することをオススメします。
内部でやり取りしているのはpromiseのインスタンスなので内部は非同期に変わりありませんが、
コード上は同期的で書けるのでわかりやすくなります。

(最後のonchangeのトリガーでresolveを返す設計上、妥協して結局promise返してますが…)

const ChangePermission = async () => {
  if('permissions' in navigator) {
    throw new Error('permissions is not in navigator');
  }
  const notificationPerm = await navigator.permissions.query({name:'notifications'});
  return new Promise((resolve, reject) => {
    notificationPerm.onchange = () => {
      if(notificationPerm.state !== "granted") return;
      console.debug('通知が許可に変更');
      resolve();
    };
  });
};

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/16 12:33

    ご回答ありがとうございます。
    そうなんですね、環境に合わせたほうがよいのですね。

    「コールバックを使う場合、第一引数はerr」
    「promiseを使いつつ、ES2017で追加されたasync / awaitを利用する」
    上記ご指摘ありがとうございます。勉強になりました。

    キャンセル

  • 2018/03/16 12:36

    あ、そうだ(唐突)

    コールバックは第一引数がerrになる関係で、
    使う側は大抵コールバック関数の1行目が`if (err)`で始まる事になります。
    つまりコードリード時はプチ邪魔な存在。

    どちらでも良い状況ならまずPromiseを使う事を考えると良いでしょう。

    キャンセル

  • 2018/03/16 12:55

    なるほど!ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.40%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • JavaScript

    21451questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • 非同期処理

    143questions

    非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。