JavaScriptのログが出なくなる場合がある

フォーラムの皆様、いつもお世話になっております。

JavaScriptカスタマイズに於いて、いくつか課題を抱えています。

①console.logの値が出なくなる場合がある

当該のJSファイルの処理は正常終了(※厳密には、エラーなしと出ています)しているにも関わらず、ログがまったく書き出されません。

かと思えば、何度か試しているうちに書き込まれる場合もあります。

対象イベントはレコード保存成功後イベントです。

成功してしまう場合があるため、原因が突き止められずにおります。

②APIを使ったPUT処理が失敗する場合がある

kintoneのレコードの登録情報を、Googlecalendarに連携させるカスタマイズをしています。

この記事

と、この記事

を参考に処理を書きましたが、失敗する理由がよくわかっておらず、困っています。

kintone.api(kintone.api.url(‘/k/v1/record’, true), ‘PUT’, kintbody,(resp) => 

それこそデバッグすればいいのでしょうが、①の問題で、console.logが出力されないので、手も足も出せなくなってしまいました。

カレンダー登録は成功し、登録した予定のeventIDをkintoneのレコードに書き込んであげる部分が、できるときとできないときがあります。

whileで成功するまで試行させつづけると、APIを無駄に消費してしまうでしょうか?

初歩的な質問ばかりで、申し訳ございません。

どうか、よろしくお願いいたします。

田中千穂様

①console.logの値が出なくなる場合がある
→console.logをコード内にいれているのに,「何も表示されない」という解釈で良いですか?

②APIを使ったPUT処理が失敗する場合がある
書かれているコードだけでは判断しきれませんが,
promiseをreturnできていない可能性が考えられます.
PUT処理付近だけでも良いのでコードを公開していただけると,回答が得られるかもしれません.

return new kintone.Promise(function (resolve, reject) {
      request.execute((resp) => {
        if (resp.error) {
          alert("イベントの登録に失敗しました。" + resp.error.message);
          resolve(false);
        } else {
            alert("イベント登録成功しました。" + resp.result.id);
            const kintbody = {
            'app': kintone.app.getId(),
            'id': record.$id.value,
            'record': {
              'event_id': {
                'value': resp.result.id
                    }
                }
            };
      kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody,(resp) => {
                }, (resp) => {
                    // error:エラーの場合はもう一回やる?検討中
                    kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody,(resp));
            });
            resolve(true);
          let appid = XXX; //開きたいアプリのID
            let nowRecordID = record.$id.value;
            if (record["もう一つ登録"].value === "あり") {
                let res = confirm("保存しました。あたらしい登録画面へ遷移します。");
                if(res){
                window.open('/k/XXX/edit?action=XXXXXXX&app=XXX&record=' + nowRecordID, '_blank');  
                }
            }
        }
      });
    });

TOさま

ご返信、ありがとうございます。

①console.logの値が出なくなる場合がある
→console.logをコード内にいれているのに,「何も表示されない」という解釈で良いですか?
完全に、仰る通りです。
console.logが出ない場合に見直す設定は見直しましたが、問題なく
また、同アプリの他JSファイルのconsole.logは常に出すことができています。

②APIを使ったPUT処理が失敗する場合がある
コードを添付いたしました。
Promiseを2つ使っていることになるという認識でおります。
Promiseについて解説を読みましたが、あまり理解できておらず……
何卒、よろしくお願いいたします。

田中千穂様

①について、chromeであればconsoleの設定で「Preserve log」にチェックが付いてますでしょうか。

https://www.jaga.biz/web-dev-javascript/chrome-preserve-log/

横から失礼します。コードを見た限り、TOさまの指摘通りPromiseを正しくreturnできていないようです。

      kintone.api(kintone.api.url('/k/v1/record',true),'PUT', kintbody,(resp) => {
                }, (resp) => {
                   // error:エラーの場合はもう一回やる?検討中
                    kintone.api(kintone.api.url('/k/v1/record',true),'PUT', kintbody,(resp));
            });
            resolve(true);

おそらく保存時(submitイベント)で走らせているかと思いますので、その前提で進めます。kintone.Promiseは実行文の中でresolve(event)を実行しない限りkintoneが次の処理に移る(submitの場合、レコードの保存処理)のを待ってくれる機能です。

プログラムは上から順に実行されますが、API等の処理(非同期処理といいます)は実行はするものの、すぐに結果を得られるわけではない(イメージとして、他の機械に「レコードの取得を行う『命令』を行う」までがこのkintone.api()というプログラムの実行文で、命令という処理が完了したため次に行きresolve()を実行してしまう=他の機械が命令の結果を得るより先にレコードの保存処理が動いてしまい、終了してしまう)ので、それを待つ処理か、結果を得られた後に次の処理を行うようにする必要があります。

コンソールが出たり出なかったり、APIが成功したりしなかったりするのはこちらが原因かと思います(サーバーのレスポンスが良くresolve()より前にレコードの取得が完了した場合は成功し、レスポンスが悪く先にresolve()が実行された場合は失敗)。

kintone.api()には引数として成功時に実行するためのsuccess functionがあるので

      kintone.api(kintone.api.url('/k/v1/record',true),'PUT', kintbody,(resp) => {
resolve(event);
     }, (error) => {
console.error(error);
});

と、この中でresolve()を実行すればレコードの取得を待って終了することができます。

以下は慣れてからで問題ありませんが、同じような処理(非同期処理)を複数繋げて行う必要がある場合

      kintone.api(kintone.api.url('/k/v1/record',true),'PUT', kintbody,(resp) => {
kintone.api(/* 略 */, (resp) => {
kintone.api(...)
}, (error) => {
console.error(error);
});
}, (error) => {
console.error(error);
});

とどんどん複雑化していきます(コールバック地獄といいます)。これを簡略化するためにPromiseやasync/awaitといったものが作られたので、Promiseを理解するためにはこの辺りから覚えていく必要があります。

また、kintone.PromiseはPromiseの存在しない古いブラウザでもPromiseが実行できるように作られたもので、resolve()をすると終了して次の処理へ移行するものの、厳密には即時ではないので

          letappid = XXX;//開きたいアプリのID
           letnowRecordID = record.$id.value;
           if(record["もう一つ登録"].value ==="あり") {
               letres = confirm("保存しました。あたらしい登録画面へ遷移します。");
               if(res){
               window.open('/k/XXX/edit?action=XXXXXXX&app=XXX&record='+ nowRecordID,'\_blank');  
                }
            }

resolve()後に実行しているこの処理は動く可能性がありますが、あまり良い形とは言えません。またedit.submitイベントであれば問題ないかと思いますが、create.submit(新規作成の保存ボタン押下時)ではレコード番号(nowRecordID)は生成されていない状態なので、保存が完了したsubmit.successで処理を行った方が良いかと思います。

ms-hashimoto様

いつもありがとうございます。懇切丁寧なご説明のおかげで、公式ドキュメントを読んでもいまいち理解できていなかった部分の理屈は理解できたと思います。

コード修正について、いくつか疑問があり、大変恐縮ですが、お教えください。

前提として、このコードはもう少し長い処理の一部であり、発火イベントは下記通りです。いくつか入力値の整合性をチェックしているので、submitではなく、正常に保存できることを担保できた状態、successが条件となります。

やりたいことは

①Google認証(出来ているので割愛)

※ここでsubmit.successを踏む

②保存されたレコードからカレンダー登録への必要値の取得、params作成。Googleカレンダーへparamsを受け渡し(出来ているので割愛)

③カレンダー登録成功のイベントを受け取ったら、そのeventIDをもとのkintoneのレコードへ入力する(promise2つめの’PUT’のところ)

④eventIDの入力も成功したら、このレコードは終了。

⑤ユーザーに新しいレコード登録を促し、新規レコード作成画面を開いてあげる

以上の手順です。③の辺りからpromiseの概念が出てきており、また、もともと前任者の方が書いてくださったコードを改変しているのですが、ご指摘のとおりJavaScript知識が乏しいままで、promiseを正しく理解・記述できていないがゆえに、こんがらがってしまっているのです。

 

いただきましたご返信拝読し、そのうえで、公式ドキュメントを見つつ、ご指摘いただきました部分をコード修正をしようと思ったのですが、resp、event、then、resolveといった要素がどう絡んでいるのかどうしても自力で解決できません。

下記の修正いただいたコードでまず引っかかってしまっています。

      kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody,(resp) => {
resolve(event);
     }, (error) => {
console.error(error);
});

ここでresolve(event);をすると、どこに返されるのでしょうか?submit.successの階層まで一気に返されてしまうのでしょうか……?

(resp)で成功の場合の値を拾っていると思っていて、respに成功のイベントが返ってこなかったら(respが空だったら)エラー処理をする…だと思っていたので、混乱しております。

公式ドキュメントを何度読んでも、少しでもコードの書き方の違う部分があると、それを自分のコードの場合に置き換えて当てはめることができずにおります…(本当に、初歩の初歩が固まっていないままなので何度も行き詰り、すみません。)

今、階層が3つあると思っています。

①submit.successの層(return eventで閉じるものと理解)

②1つめのpromise(カレンダー登録実行)(resolve(false)とresolve(true)で閉じている様子。前任者の書いてくれた部分です。)

③2つめのpromise(kintone.api(kintone.api.url(‘/k/v1/record’, true), ‘PUT’, kintbody,(resp) => {○×○× (これはreturn(resp)なのか、return(event)なのか、理解できておらず)

③をちゃんと閉じてあげる。そのあとに②を閉じてあげる。最後に①をちゃんと終わらせる。

その整理を、今一度ご助力願えないでしょうか…… コールバック地獄に陥っているのですね、解読も難儀すると思い、申し訳ない限りです……

ご多忙の折、お手数おかけし、申し訳ございません。

下記、コードです。

(function googleCalendarAlignment() {
  "use strict";
kintone.events.on(["app.record.create.submit.success", "app.record.edit.submit.success"],
    (event) => {
//ここでカレンダー登録を実行するための処理を行っています(省略)

    //条件を満たしたので、カレンダー処理を呼び出す。
    return upsertCalendar(recordId, record);

//この辺ではGoogleカレンダー用のparamを作成したりする処理を行っています(省略)

  // ここまで無事に来たので、Googleカレンダーへのイベント登録の実行。呼び出し非同期処理として受け取れるよう、Promise化
return new kintone.Promise(function (resolve, reject) {
      request.execute((resp) => {
        if (resp.error) {
          alert("イベントの登録に失敗しました。" + resp.error.message);
          resolve(false);
        } else {
            alert("イベント登録成功しました。" + resp.result.id);
            const kintbody = {
            'app': kintone.app.getId(),
            'id': record.$id.value,
            'record': {
              'event_id': {
                'value': resp.result.id
                    }
                }
            };
      kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody,(resp) => {
        //ここにreturn(event);を置くとどこの階層までリターンするのでしょうか…?respとeventの使い分けがわかっていません…
                }, (resp) => {
                    // error:エラーの場合はもう一回やる?検討中
                    kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody,(resp));
            });
            resolve(true);//←←これは本来どこに置かれるべきなのでしょうか…
          let appid = XXX; //開きたいアプリのID
            let nowRecordID = record.$id.value;
            if (record["もう一つ登録"].value === "あり") {
                let res = confirm("保存しました。あたらしい登録画面へ遷移します。");
                if(res){
                window.open('/k/XXX/edit?action=XXXXXXX&app=XXX&record=' + nowRecordID, '_blank');  
                }
            }
        }
      });
  });

momochiさま

ご返信遅くなり、申し訳ございません。

当該の設定は、変更していませんでしたので、ご指摘の通りに変更しました。

ありがとうございます。

田中千穂 

ご質問なのですが、

return upsertCalendar(recordId, record);

と書かれているのですが、upsertCalendar関数が終了してしまうと、現状ですと戻り値として変数を宣言していないため、処理も終了してしまうのではないのでしょうか?

他の関数のコードがないため、Googleカレンダーへのイベント実行以下のコードになりますが、そのまま利用させて頂くと、このような形になるのではないのでしょうか?

return new kintone.Promise(function (resolve, reject) {
              request.execute((resp) => {
                  if (resp.error) {
                      alert("イベントの登録に失敗しました。" + resp.error.message);
                      resolve(false);
                  } else {
                      alert("イベント登録成功しました。" + resp.result.id);
                      const kintbody = {
                          'app': kintone.app.getId(),
                          'id': record.$id.value,
                          'record': {
                              'event_id': {
                                  'value': resp.result.id
                              }
                          }
                      };
                      return kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody, (resp) => {
                          let appid = XXX; //開きたいアプリのID
                          let nowRecordID = record.$id.value;
                          if (record["もう一つ登録"].value === "あり") {
                              let res = confirm("保存しました。あたらしい登録画面へ遷移します。");
                              if (res) {
                                  window.open('/k/XXX/edit?action=XXXXXXX&app=XXX&record=' + nowRecordID, '_blank');
                              }
                          }
                          resolve(true);
                      }, (error) => {
                          // error:エラーの場合はもう一回やる?検討中
                          console.log(error);
                          return kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', kintbody, (resp) => {
                              let appid = XXX; //開きたいアプリのID
                              let nowRecordID = record.$id.value;
                              if (record["もう一つ登録"].value === "あり") {
                                  let res = confirm("保存しました。あたらしい登録画面へ遷移します。");
                                  if (res) {
                                      window.open('/k/XXX/edit?action=XXXXXXX&app=XXX&record=' + nowRecordID, '_blank');
                                  }
                              }
                              resolve(true);
                          }, (error) => {
                              console.log(error);
                              resolve(false);
                          }
                          );
                      });
                  }
              });
          });

なお、基本的にPUTでエラーした際にもう一度されない方がいいかと思われます。

こちら、コードを修正することで改善しました。

※大幅な改修があり、載せきれないので、割愛させていただいております。

皆様、ありがとうございました。

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。