初めまして。
プロジェクトでkintoneでの開発を検討している者です。
PL/SQLやストアドプロシージャでの開発業務経験はありますが
kintone,javascript共に初心者です。
検証している際に詰まってしまったので質問させていただきます。
一覧画面にボタンを追加し、
そこで呼び出した関数内でGETした結果をreturnしようとしています。
試したところ取得結果が返却されずundefinedになってしまいます。
chromeでデバックしたところ、
ボタンのonclickイベントが終了してからGETのレスポンスが返却されているように見えます。
その時のGETのレスポンス自体は取得したい値でした。
お手数ですが何がいけないのかご教授いただけないでしょうか。
以下にコードを貼付します。
(function () {
"use strict";
//レコード一覧表示時
kintone.events.on('app.record.index.show', function(event) {
var myIndexButton = document.createElement('button');
myIndexButton.id = 'my_index_button';
myIndexButton.innerHTML = 'test';
// ボタンクリック時の処理
myIndexButton.onclick = function() {
//アプリIDを取得してアラートに表示する
var appId = new testfunc();
window.alert(appId);
};
kintone.app.getHeaderMenuSpaceElement().appendChild(myIndexButton);
});
function testfunc(){
var appId;
//GET処理のテスト
//指定したアプリのアプリIDを取得する
var body = {"name":"testアプリ"};
kintone.api(kintone.api.url('/k/v1/apps', true), 'GET', body, function(resp) {
// success
appId = resp.apps[0].appId
}, function(error) {
// error
console.log(error);
});
return appId;
}
})();
結論から言いますと、ご察しの通り、APIからの返却が終る前にreturnしてしまっているのが問題です。
Callbackに処理を書く必要があります。
kintone.api(kintone.api.url('/k/v1/apps', true), 'GET', body, function(resp) {
// success
appId = resp.apps[0].appId
window.alert(appId); // ここに処理を書く
myFunc(appId); // 独自で定義したFunctionなどを実行してもいい
}, function(error) {
// error
console.log(error);
});
もしくは kintone.Promiseという仕組みを使うこともできますが、まずは上記に慣れたほうがいいかと思います。
コールバックのネストが辛い場合などにPromiseが役に立ちますので、調べてみて下さい。
ここからは蛇足です
JavaScriptの特性として、シングルスレッドで動いていることが挙げられます。
よって、今回の用にAPIの返却をWaitしてしまうと、ブラウザ全体が止まってしまうので、
通信処理やファイル処理は基本的に非同期になっている、ということを念頭におくといいと思います。
村濱様
コメントありがとうございます。
起こっている現象については理解できました。
APIの結果を受け取るにはコールバックが必要という事ですね。
教えていただいたpromiseについても少しですが調べてみました。
非同期処理であるREST APIを順序性を持って実行したいケースで、
コールバックで記述すると処理をネストしていく必要があり、
場合によってはネストがどんどん深くなってしまう。
promiseを利用するとネストの深さと可読性の低さを解消する事ができる。
このような理解で宜しいでしょうか?
promiseの仕様について理解がまだまだなので表面しか理解できていないとは思いますが。。。
それから、これはコードの書き方の問題なのですがAPIの実行結果を取得して利用する場合以下のような
記述では望通りの結果は得られないという理解で間違っていないでしょうか?
処理の流れはtestfunc1及びtestfunc2の処理が完了して結果を取得してからtestfunc3を呼び出したいケースとなります。
意図としてはRESTAPIを実行する部分の処理をfunctionで切り出して実行結果を返す関数を用意したかったです。
(function () {
"use strict";
//レコード一覧表示時
kintone.events.on('app.record.index.show', function(event) {
var result1; //API実行結果格納用
var result2; //API実行結果格納用
//GETAPIを使用して結果を取得
result1 = testfunc1();
result2 = testfunc2();
//result1とresult2の値を引数にfunctionを呼び出し
testfunc3(result1,result2);
});
function testfunc1(){
//RESTAPI実行
//結果をreturnする
}
function testfunc2(){
//RESTAPI実行
//結果をreturnする
}
function testfunc3(result1,result2){
//testfunc1とtestfunc2から返却されたAPIの実行結果を利用して何らかの処理を実行する
}
原則しとしてはコールバックを駆使するとこんな感じです。
// 1つ目のAPI
kintone.api('/k/v1/record', 'GET', params1, function(resp1) {
// 1つ目のAPIが成功したら2つ目のAPIを実行
kintone.api('/k/v1/record', 'GET', params2, function(resp2) {
// 両方成功した場合, APIによって取得した両方のデータを使える
console.log(resp1, resp2);
}, function(resp) {
// 2つ目のAPIのエラー
});
}, function(resp) {
// 1つ目のAPIのエラー
});
関数にしたければ下記のような風になります。
JavaScriptは関数もリテラルですので、func1の引数に関数func2をいれてるのがポイントです
※動作確認はしてません。
function func1(callbackFunc) {
kintone.api('/k/v1/record', 'GET', params1, function(resp1) {
// APIが成功したらCallBackを呼ぶ
callbackFunc(resp1);
}, function(resp) {
// APIのエラー
});
}
function func2(resp1) {
kintone.api('/k/v1/record', 'GET', params2, function(resp2) {
// 引数のデータとこのFunctionで取得したものを表示
console.log(resp1, resp2);
}, function(resp) {
// APIのエラー
});
}
// 実行
func1(func2);
上記をみてもわかるとおり、コールバックが深くなると面倒なので、
Promiseを学習して、使いこなせるようになるのであればそっちのほうがいいかとは思います。
Promiseの場合は、Whenなど、すべての非同期処理がおわったら、次の処理を実行するという関数もありますので、
しらべてみてください。