Я занимаюсь разработкой приложения App Maker, и из клиентского скрипта я должен вызывать функции на стороне сервера - предположим, что функция a
и функция b
- зависят отдруг друга.
Первым (нативным) решением в клиентском скрипте было следующее, которое использует обратные вызовы:
function doB(s) {
google.script.run.withSuccessHandler(function(result) { // async workload
console.log(result);
}).withFailureHandler(function(error) {
console.log(error);
}).b(s);
}
function aThenB(s) {
google.script.run.withSuccessHandler(function(result) { // async workload
console.log(result);
doB(result); // call b
}).withFailureHandler(function(error) {
console.log(error);
}).a(s);
}
Но если вам нужно затем вызвать функцию c
, изатем d
и т. д., с результатами выполнения этих связанных функций, это становится очень громоздким.Я прочитал эту статью , которая описывает преобразование из обратного вызова в Promise, например:
function runnerToPromise(f) {
var runArgs = Array.prototype.slice.call(arguments).slice(1);
return new Promise(function(resolve, reject) { // executor
google.script.run.withSuccessHandler(function(result) {
resolve(result); // resolve promise
}).withFailureHandler(function(error) {
reject(error); // reject promise
})[f].apply(this, runArgs); // async
});
}
, что сделало бы приведенный выше код похожим на:
function aThenB(s) {
return runnerToPromise('a', s).then(
function(result) {
return runnerToPromise('b', result);
}
);
}
function runAThenB(s) {
aThenB(s).then(function(result) {
console.log('SUCCESS: ' + result);
}).catch(function(error) {
console.log(error);
});
}
Это решение работает правильно, если вы используете Apps Script и HtmlService
и развертываете скрипт как «Веб-приложение».
Однако в App Maker выдается ошибка, которую я не могу понять:
TypeError: Невозможно прочитать свойство 'withLogger' из неопределенного.
Как устранить эту ошибку только для App Maker?
UPDATE
Я создал новое тестовое приложение с App Maker для воспроизведения проблемы.
Приложение просто делает это: оно копирует, в два шага, данные из электронной таблицы в другую электронную таблицу.
Я запустил код в App Maker и развернул его как веб-приложение, созданное с помощью скрипта Apps.
Нет проблем с веб-приложением, созданным с помощью скрипта Apps;в App Maker правильно работает только решение, использующее обратные вызовы.
Сценарий на стороне сервера:
function serverStepOne() {
console.log('serverStepOne fn called!');
return SpreadsheetApp
.openById('XXX') // Spreadsheet A
.getSheetByName('A')
.getDataRange()
.getValues();
}
function serverStepTwo(grid) {
console.log('serverStepTwo fn called!');
SpreadsheetApp
.openById('YYY') // Spreadsheet B
.getSheetByName('A').getRange(1, 1, grid.length, grid[0].length).setValues(grid); // all rows have the same number of cells
return 'copy done!';
}
Сценарий на стороне клиента:
function copyData() { // messy one... works like a charm in App Maker
google.script.run.withSuccessHandler(function(result) {
google.script.run.withSuccessHandler(function(result) {console.log(result);}).withFailureHandler(function(error) {console.log(error);}).serverStepTwo(result);
}).withFailureHandler(function(error) {console.log(error);}).serverStepOne();
}
function runnerToPromise(f) {
var runArgs = Array.prototype.slice.call(arguments).slice(1);
return new Promise(function(resolve, reject) {
google.script.run.withSuccessHandler(function(result) {
resolve(result);
}).withFailureHandler(function(error) {
reject(error);
})[f].apply(this, runArgs);
});
}
function copyDataPromise() { // tidy one... doesn't work in App Maker; works in Apps Script Web App
return runnerToPromise('serverStepOne').then(
function(result) {
return runnerToPromise('serverStepTwo', result);
});
}
function runCopyDataPromise() {
copyDataPromise().then(function(result) {console.log(result);}).catch(function(error) {console.log(error);});
}
App Maker, когда copyDataPromiseВызывается fn, создает следующий журнал в консоли браузера:
com.google.apps.appmaker.AppMakerGwt-0.js:7706 Uncaught (in promise) TypeError: Cannot read property 'withLogger' of undefined
at n.(n-omfqufplv3inu3qxlfsar7h6wn2rogznri3mjoq-0lu-script.googleusercontent.com/anonymous function) (com.google.apps.appmaker.AppMakerGwt-0.js:7706:182)
at clientScriptsContext.js:14
at <anonymous>:26:11
at new Promise (<anonymous>)
at runnerToPromise (<anonymous>:16:10)
at copyDataPromise (<anonymous>:32:10)
at COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick (<anonymous>:48:1)
at window.am_exit (clientScriptsContext.js:22)
at UZ (com.google.apps.appmaker.AppMakerGwt-0.js:6651)
at LZ (com.google.apps.appmaker.AppMakerGwt-0.js:4950)
at NZ (com.google.apps.appmaker.AppMakerGwt-0.js:6043)
at Qgb (com.google.apps.appmaker.AppMakerGwt-0.js:6803)
at QTb.RTb [as sc] (com.google.apps.appmaker.AppMakerGwt-0.js:7738)
at ozd.pzd [as xd] (com.google.apps.appmaker.AppMakerGwt-0.js:7746)
at wCd (com.google.apps.appmaker.AppMakerGwt-0.js:7328)
at oCd (com.google.apps.appmaker.AppMakerGwt-0.js:6718)
at Id (com.google.apps.appmaker.AppMakerGwt-0.js:1394)
at Wyd (com.google.apps.appmaker.AppMakerGwt-0.js:6732)
at Kd (com.google.apps.appmaker.AppMakerGwt-0.js:6025)
at PHc.Vd [as dc] (com.google.apps.appmaker.AppMakerGwt-0.js:7728)
at pue (com.google.apps.appmaker.AppMakerGwt-0.js:5477)
at HTMLButtonElement.Vve (com.google.apps.appmaker.AppMakerGwt-0.js:4828)
at Drd (com.google.apps.appmaker.AppMakerGwt-0.js:2887)
at Grd (com.google.apps.appmaker.AppMakerGwt-0.js:6717)
at HTMLButtonElement.eval (com.google.apps.appmaker.AppMakerGwt-0.js:4677)
n.(anonymous function) @ com.google.apps.appmaker.AppMakerGwt-0.js:7706
(anonymous) @ clientScriptsContext.js:14
(anonymous) @ VM28:26
runnerToPromise @ VM28:16
copyDataPromise @ VM28:32
COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick @ VM38:48
window.am_exit @ clientScriptsContext.js:22
UZ @ com.google.apps.appmaker.AppMakerGwt-0.js:6651
LZ @ com.google.apps.appmaker.AppMakerGwt-0.js:4950
NZ @ com.google.apps.appmaker.AppMakerGwt-0.js:6043
Qgb @ com.google.apps.appmaker.AppMakerGwt-0.js:6803
RTb @ com.google.apps.appmaker.AppMakerGwt-0.js:7738
pzd @ com.google.apps.appmaker.AppMakerGwt-0.js:7746
wCd @ com.google.apps.appmaker.AppMakerGwt-0.js:7328
oCd @ com.google.apps.appmaker.AppMakerGwt-0.js:6718
Id @ com.google.apps.appmaker.AppMakerGwt-0.js:1394
Wyd @ com.google.apps.appmaker.AppMakerGwt-0.js:6732
Kd @ com.google.apps.appmaker.AppMakerGwt-0.js:6025
Vd @ com.google.apps.appmaker.AppMakerGwt-0.js:7728
pue @ com.google.apps.appmaker.AppMakerGwt-0.js:5477
Vve @ com.google.apps.appmaker.AppMakerGwt-0.js:4828
Drd @ com.google.apps.appmaker.AppMakerGwt-0.js:2887
Grd @ com.google.apps.appmaker.AppMakerGwt-0.js:6717
(anonymous) @ com.google.apps.appmaker.AppMakerGwt-0.js:4677
Promise.then (async)
copyDataPromise @ VM28:32
COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick @ VM38:48
window.am_exit @ clientScriptsContext.js:22
UZ @ com.google.apps.appmaker.AppMakerGwt-0.js:6651
LZ @ com.google.apps.appmaker.AppMakerGwt-0.js:4950
NZ @ com.google.apps.appmaker.AppMakerGwt-0.js:6043
Qgb @ com.google.apps.appmaker.AppMakerGwt-0.js:6803
RTb @ com.google.apps.appmaker.AppMakerGwt-0.js:7738
pzd @ com.google.apps.appmaker.AppMakerGwt-0.js:7746
wCd @ com.google.apps.appmaker.AppMakerGwt-0.js:7328
oCd @ com.google.apps.appmaker.AppMakerGwt-0.js:6718
Id @ com.google.apps.appmaker.AppMakerGwt-0.js:1394
Wyd @ com.google.apps.appmaker.AppMakerGwt-0.js:6732
Kd @ com.google.apps.appmaker.AppMakerGwt-0.js:6025
Vd @ com.google.apps.appmaker.AppMakerGwt-0.js:7728
pue @ com.google.apps.appmaker.AppMakerGwt-0.js:5477
Vve @ com.google.apps.appmaker.AppMakerGwt-0.js:4828
Drd @ com.google.apps.appmaker.AppMakerGwt-0.js:2887
Grd @ com.google.apps.appmaker.AppMakerGwt-0.js:6717
(anonymous) @ com.google.apps.appmaker.AppMakerGwt-0.js:4677
В Stackdriver вообще нет ошибок.
ОБНОВЛЕНИЕ 2
I 'Мы немного изменили код, добавив выражения именованных функций.
function runnerToPromise(f) {
var runArgs = Array.prototype.slice.call(arguments).slice(1);
return new Promise(function myExecutor(resolve, reject) {
google.script.run.withSuccessHandler(function myWithSuccessHandler(result) {
resolve(result);
}).withFailureHandler(function myWithFailureHandler( error) {
reject(error);
})[f].apply(null, runArgs);
});
}
function copyDataPromise() { // tidy one... doesn't work at all in App Maker; works with Apps Script (Web App)
return runnerToPromise('serverStepOne').then(
function myFirstPromiseThen(result) {
return runnerToPromise('serverStepTwo', result);
});
}
function runCopyDataPromise() {
copyDataPromise().then(function myLastPromiseThen(result) {console.log(result);}).catch(function myFinalCatch(error) {console.log(error);});
}
Журнал консоли:
com.google.apps.appmaker.AppMakerGwt-0.js:formatted:57540 Uncaught (in promise) TypeError: Cannot read property 'withLogger' of undefined
at n.(n-omfqufplv3inu3qxlfsar7h6wn2rogznri3mjoq-0lu-script.googleusercontent.com/anonymous function) (com.google.apps.appmaker.AppMakerGwt-0.js:7706:182)
at clientScriptsContext.js:14
at myExecutor (<anonymous>:26:11)
at new Promise (<anonymous>)
at runnerToPromise (<anonymous>:16:10)
at copyDataPromise (<anonymous>:32:10)
at COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick (<anonymous>:48:1)
at window.am_exit (clientScriptsContext.js:22)
at UZ (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36031)
at LZ (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:20165)
at NZ (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:29107)
at Qgb (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:38046)
at QTb.RTb [as sc] (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:77339)
at ozd.pzd [as xd] (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:93227)
at wCd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:46855)
at oCd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36933)
at Id (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:3853)
at Wyd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:37133)
at Kd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:28919)
at PHc.Vd [as dc] (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:61727)
at pue (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:23899)
at HTMLButtonElement.Vve (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:19342)
at Drd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:9567)
at Grd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36910)
at HTMLButtonElement.eval (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:18425)
n.(anonymous function) @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:57540
(anonymous) @ clientScriptsContext.js:14
myExecutor @ VM28:26
runnerToPromise @ VM28:16
copyDataPromise @ VM28:32
COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick @ VM72:48
window.am_exit @ clientScriptsContext.js:22
UZ @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36031
LZ @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:20165
NZ @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:29107
Qgb @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:38046
RTb @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:77339
pzd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:93227
wCd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:46855
oCd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36933
Id @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:3853
Wyd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:37133
Kd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:28919
Vd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:61727
pue @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:23899
Vve @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:19342
Drd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:9567
Grd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36910
(anonymous) @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:18425
Promise.then (async)
copyDataPromise @ VM28:32
COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick @ VM72:48
window.am_exit @ clientScriptsContext.js:22
UZ @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36031
LZ @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:20165
NZ @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:29107
Qgb @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:38046
RTb @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:77339
pzd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:93227
wCd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:46855
oCd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36933
Id @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:3853
Wyd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:37133
Kd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:28919
Vd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:61727
pue @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:23899
Vve @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:19342
Drd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:9567
Grd @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36910
(anonymous) @ com.google.apps.appmaker.AppMakerGwt-0.js:formatted:18425
ОБНОВЛЕНИЕ 3
Я попробовал код ниже.Он работает в веб-приложении скриптовых приложений.Это не работает в App Maker.В App Maker выдает ту же ошибку: Невозможно прочитать свойство 'withLogger' из неопределенного
/*jshint esnext:true*/
const runnerToPromiseSpread = (fn, ...args) => {
return new Promise((resolve, reject) => {
let task = google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject);
if (task[fn] === undefined) {
reject("'" + fn + "' is not a global function in your Apps Script project");
} else {
task[fn].apply(null, args);
}
});
};
function copyDataPromiseSpread() {
return runnerToPromiseSpread('serverStepOne')
.then((result) => {
return runnerToPromiseSpread('serverStepTwo', result);
});
}
function runCopyDataPromiseSpread() {
copyDataPromiseSpread().then((result) => {
console.log(result);
}).catch((error) => {
console.log(error);
});
}
В консоли браузера:
TypeError: Cannot read property 'withLogger' of undefined
at n.(n-omfqufplv3inu3qxlfsar7h6wn2rogznri3mjoq-0lu-script.googleusercontent.com/anonymous function) (com.google.apps.appmaker.AppMakerGwt-0.js:7706:182)
at clientScriptsContext.js:14
at <anonymous>:21:16
at new Promise (<anonymous>)
at runnerToPromiseSpread (<anonymous>:7:10)
at copyDataPromiseSpread (<anonymous>:28:10)
at runCopyDataPromiseSpread (<anonymous>:39:5)
at COMPONENT_EVENT_1sVF9N7aiAUX2sXc4qZ90Ben2JowEfeez_0_1142335744_onClick (<anonymous>:86:1)
at window.am_exit (clientScriptsContext.js:22)
at UZ (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36031)
at LZ (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:20165)
at NZ (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:29107)
at Qgb (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:38046)
at QTb.RTb [as sc] (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:77339)
at ozd.pzd [as xd] (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:93227)
at wCd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:46855)
at oCd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36933)
at Id (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:3853)
at Wyd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:37133)
at Kd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:28919)
at PHc.Vd [as dc] (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:61727)
at pue (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:23899)
at HTMLButtonElement.Vve (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:19342)
at Drd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:9567)
at Grd (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:36910)
at HTMLButtonElement.eval (com.google.apps.appmaker.AppMakerGwt-0.js:formatted:18425)