来自 Google Apps 脚本的 ContactsApp.getContacts() 未按预期运行
ContactsApp.getContacts() from Google Apps Script does not behave as expected
我有一个脚本可以将所有联系人从 Google 联系人获取到 Google 工作表中的传播sheet。由于6分钟执行时限内联系人太多,我使用脚本触发一段时间后继续导入。
...
var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length; ++i){
// register trigger if time is up
// ....
var name = contacts[i].getFullName();
sheet.appendRow([name]);
}
...
什么有效:
- 当达到时间限制时(我将其设置为 4 分钟),触发器会 运行 并继续导入。
什么不起作用:
- 执行链会在某个点随机停止,导致导入不完整。
- 即使联系人的大小小到可以在 4 分钟内获取,导入的联系人数量有时也与 contacts.length 不匹配。大多数时候它会匹配。
- 补偿(1)。我制作了一个新菜单,以继续从最后一个索引导入,该索引源自 sheet 中写入的总行数。但是,当以这种方式完成时,导入的联系人将从第一个索引开始,无论我要求脚本从哪个索引开始。
例如:
for(var i = last_row;i<contacts.length;++i){ // I've checked last_row is indeed not 0
var name = contacts[i].getFullName();
// append row
}
将产生与以下相同的结果:
for(var i = 0;i<contacts.length;++i){
var name = contacts[i].getFullName();
// append row
}
无论我要求从哪个索引开始,它总是从联系人数组的第一个索引开始,除非它是从触发器链中执行的。谁能告诉我这是怎么回事?我该如何解决这个问题?
在您的脚本中,appendRow
用于循环。在这种情况下,工艺成本变高。 Ref 我猜想这可能是您处理时间的原因。如果我对你的问题的理解是正确的,那么下面的修改怎么样?
发件人:
var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length; ++i){
// register trigger if time is up
// ....
var name = contacts[i].getFullName();
sheet.appendRow([name]);
}
收件人:
var contacts = ContactsApp.getContacts();
var values = contacts.map(e => [e.getFullName()]);
sheet.getRange(sheet.getLastRow() + 1, 1, values.length).setValues(values);
- 在此修改中,将值放入一个数组,然后使用
setValues
将该数组放入 Spreadsheet。据此,我认为这个过程可能是运行一次执行。
另一种方法:
作为另一种方法,使用 People API 怎么样?当使用 People API 时,示例脚本如下。如果你使用这个脚本,please enable People API at Advanced Google services.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var values = [];
var pageToken = "";
do {
var o1 = People.People.Connections.list("people/me", { personFields: "names", fields: "connections.names.displayName,nextPageToken", pageSize: 1000, pageToken });
if (o1.connections.length > 0) {
values.push(...o1.connections.map(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
}
pageToken = o1.nextPageToken;
} while (pageToken);
do {
var o2 = People.OtherContacts.list({ readMask: "names", fields: "otherContacts.names.displayName,nextPageToken", pageSize: 1000, pageToken });
if (o2.otherContacts.length > 0) {
values.push(...o2.otherContacts.flatMap(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
}
pageToken = o2.nextPageToken;
} while (pageToken);
sheet.getRange(sheet.getLastRow() + 1, 1, values.length).setValues(values);
}
- 在此示例中,值被放入活动 sheet。请根据实际情况修改。
参考文献:
我有一个脚本可以将所有联系人从 Google 联系人获取到 Google 工作表中的传播sheet。由于6分钟执行时限内联系人太多,我使用脚本触发一段时间后继续导入。
...
var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length; ++i){
// register trigger if time is up
// ....
var name = contacts[i].getFullName();
sheet.appendRow([name]);
}
...
什么有效:
- 当达到时间限制时(我将其设置为 4 分钟),触发器会 运行 并继续导入。
什么不起作用:
- 执行链会在某个点随机停止,导致导入不完整。
- 即使联系人的大小小到可以在 4 分钟内获取,导入的联系人数量有时也与 contacts.length 不匹配。大多数时候它会匹配。
- 补偿(1)。我制作了一个新菜单,以继续从最后一个索引导入,该索引源自 sheet 中写入的总行数。但是,当以这种方式完成时,导入的联系人将从第一个索引开始,无论我要求脚本从哪个索引开始。
例如:
for(var i = last_row;i<contacts.length;++i){ // I've checked last_row is indeed not 0
var name = contacts[i].getFullName();
// append row
}
将产生与以下相同的结果:
for(var i = 0;i<contacts.length;++i){
var name = contacts[i].getFullName();
// append row
}
无论我要求从哪个索引开始,它总是从联系人数组的第一个索引开始,除非它是从触发器链中执行的。谁能告诉我这是怎么回事?我该如何解决这个问题?
在您的脚本中,appendRow
用于循环。在这种情况下,工艺成本变高。 Ref 我猜想这可能是您处理时间的原因。如果我对你的问题的理解是正确的,那么下面的修改怎么样?
发件人:
var contacts = ContactsApp.getContacts();
var last_index = parseInt(userProperties.getProperty('last_index'));
if(isNaN(last_index)) last_index = 0;
for(var i = last_index; i < contacts.length; ++i){
// register trigger if time is up
// ....
var name = contacts[i].getFullName();
sheet.appendRow([name]);
}
收件人:
var contacts = ContactsApp.getContacts();
var values = contacts.map(e => [e.getFullName()]);
sheet.getRange(sheet.getLastRow() + 1, 1, values.length).setValues(values);
- 在此修改中,将值放入一个数组,然后使用
setValues
将该数组放入 Spreadsheet。据此,我认为这个过程可能是运行一次执行。
另一种方法:
作为另一种方法,使用 People API 怎么样?当使用 People API 时,示例脚本如下。如果你使用这个脚本,please enable People API at Advanced Google services.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var values = [];
var pageToken = "";
do {
var o1 = People.People.Connections.list("people/me", { personFields: "names", fields: "connections.names.displayName,nextPageToken", pageSize: 1000, pageToken });
if (o1.connections.length > 0) {
values.push(...o1.connections.map(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
}
pageToken = o1.nextPageToken;
} while (pageToken);
do {
var o2 = People.OtherContacts.list({ readMask: "names", fields: "otherContacts.names.displayName,nextPageToken", pageSize: 1000, pageToken });
if (o2.otherContacts.length > 0) {
values.push(...o2.otherContacts.flatMap(e => e.names ? e.names.map(f => [f.displayName]) : [[""]]));
}
pageToken = o2.nextPageToken;
} while (pageToken);
sheet.getRange(sheet.getLastRow() + 1, 1, values.length).setValues(values);
}
- 在此示例中,值被放入活动 sheet。请根据实际情况修改。