使用递归方法异步
Async with recursive method
我正在尝试创建一种方法,使用驱动器 API 复制 google 驱动器中的文件夹树。我遇到了一些异步方法不起作用的问题,如果有人能发现代码中的缺陷,或者向我指出一些有用的文章,那将非常有帮助。
我需要等待导致错误的行,因为下一个递归调用需要 'copy' 函数所需的文件夹 ID。它 returns 一个承诺,所以它看起来应该有效。
总的来说,我对异步编程不是很有经验,所以我可能会忽略一些简单的东西,但我已经坚持了一段时间了。谢谢!!
代码:
function authorize() {
const auth = new google.auth.GoogleAuth({
keyFile: 'creds.json',
scopes: SCOPES
})
return google.drive({version: 'v3', auth})
}
function search(driveService, parentFolder) {
return new Promise((resolve, reject) => {
driveService.files.list({
pageSize: 20,
q: `'${parentFolder}' in parents and trashed = false`,
fields: 'files(id, name, mimeType)'
}).then(({data}) => resolve(data))
.catch(err => reject(err))
})
}
function createRoot(driveService, CLIENT_NAME, NEW_FOLDER_LOCATION) {
let fileMetadata = {
'name': CLIENT_NAME,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [NEW_FOLDER_LOCATION]
}
return new Promise((resolve, reject) => {
const file = driveService.files.create({
resource: fileMetadata,
fields: 'id'
}, function(err, file) {
if(err) {
reject(err);
} else {
resolve(file.data.id);
}
})
})
}
function copy(driveService, copyContentId, contentNewName, root){
let fileMetadata = {
'name': contentNewName,
'parents': [root]
};
return new Promise((resolve, reject) => {
const file = driveService.files.copy({
'fileId': copyContentId,
'resource': fileMetadata
}, function(err, file) {
if(err) {
reject(err);
} else {
resolve(file.data.id);
}
})
})
}
async function recursive(driveService, startSearch, rootFolder) {
let children = await search(driveService, startSearch);
if(children.files.length > 0) {
children.files.forEach((element) => {
if(element.mimeType === 'application/vnd.google-apps.folder') {
let name = element.name.replace('Last, First', CLIENT_NAME);
let folderID = await copy(driveService, element.id, name, rootFolder);
recursive(driveService, element.id, folderID);
} else {
let name = element.name.replace('Last, First', CLIENT_NAME);
let fileID = await copy(driveService, element.id, name, rootFolder);
}
})
} else {
console.log('end of branch');
}
}
async function run() {
try{
const google = await authorize();
const root = await createRoot(google, CLIENT_NAME, NEW_FOLDER_LOCATION);
await recursive(google, START_SEARCH, root);
} catch(err) {
console.log('error', err);
}
}
run();
输出:
app.js:75
let folderID = await copy(driveService, element.id, name, rootFolder);
^^^^^
SyntaxError: await is only valid in async functions and the top level bodies of modules
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1031:15)
at Module._compile (node:internal/modules/cjs/loader:1065:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
切换自
children.files.forEach(element => { ... })
至:
for (let element of children.files) { ...}
并且,改变这个:
recursive(driveService, element.id, folderID);
对此:
await recursive(driveService, element.id, folderID);
您想切换 .forEach()
,这样您就不会创建新的函数作用域,这样您就可以使用 await
,这样 await
就会暂停父函数。 .forEach()
回调中的新函数未声明 [=18=] 这就是您收到错误的原因(您不能在该回调函数中使用 await
)。并且,将该回调声明为 async
将使错误消失,但不会执行您想要的操作,因为它不会暂停父函数。
.forEach()
不 async/await 知道。不要在这种情况下使用它。
我什至可以说 .forEach()
现在已经过时了。由于 for/of
和 let/const
是块范围的并且 .forEach()
不支持 async/await
有很多理由避免 .forEach()
并且没有理由使用它。
您需要 await recursive(...)
以便将新的 promise 链绑定到当前的 promise 链,而不是创建一个全新的独立 promise 链,调用者不知道它何时完成。
我正在尝试创建一种方法,使用驱动器 API 复制 google 驱动器中的文件夹树。我遇到了一些异步方法不起作用的问题,如果有人能发现代码中的缺陷,或者向我指出一些有用的文章,那将非常有帮助。
我需要等待导致错误的行,因为下一个递归调用需要 'copy' 函数所需的文件夹 ID。它 returns 一个承诺,所以它看起来应该有效。
总的来说,我对异步编程不是很有经验,所以我可能会忽略一些简单的东西,但我已经坚持了一段时间了。谢谢!!
代码:
function authorize() {
const auth = new google.auth.GoogleAuth({
keyFile: 'creds.json',
scopes: SCOPES
})
return google.drive({version: 'v3', auth})
}
function search(driveService, parentFolder) {
return new Promise((resolve, reject) => {
driveService.files.list({
pageSize: 20,
q: `'${parentFolder}' in parents and trashed = false`,
fields: 'files(id, name, mimeType)'
}).then(({data}) => resolve(data))
.catch(err => reject(err))
})
}
function createRoot(driveService, CLIENT_NAME, NEW_FOLDER_LOCATION) {
let fileMetadata = {
'name': CLIENT_NAME,
'mimeType': 'application/vnd.google-apps.folder',
'parents': [NEW_FOLDER_LOCATION]
}
return new Promise((resolve, reject) => {
const file = driveService.files.create({
resource: fileMetadata,
fields: 'id'
}, function(err, file) {
if(err) {
reject(err);
} else {
resolve(file.data.id);
}
})
})
}
function copy(driveService, copyContentId, contentNewName, root){
let fileMetadata = {
'name': contentNewName,
'parents': [root]
};
return new Promise((resolve, reject) => {
const file = driveService.files.copy({
'fileId': copyContentId,
'resource': fileMetadata
}, function(err, file) {
if(err) {
reject(err);
} else {
resolve(file.data.id);
}
})
})
}
async function recursive(driveService, startSearch, rootFolder) {
let children = await search(driveService, startSearch);
if(children.files.length > 0) {
children.files.forEach((element) => {
if(element.mimeType === 'application/vnd.google-apps.folder') {
let name = element.name.replace('Last, First', CLIENT_NAME);
let folderID = await copy(driveService, element.id, name, rootFolder);
recursive(driveService, element.id, folderID);
} else {
let name = element.name.replace('Last, First', CLIENT_NAME);
let fileID = await copy(driveService, element.id, name, rootFolder);
}
})
} else {
console.log('end of branch');
}
}
async function run() {
try{
const google = await authorize();
const root = await createRoot(google, CLIENT_NAME, NEW_FOLDER_LOCATION);
await recursive(google, START_SEARCH, root);
} catch(err) {
console.log('error', err);
}
}
run();
输出:
app.js:75
let folderID = await copy(driveService, element.id, name, rootFolder);
^^^^^
SyntaxError: await is only valid in async functions and the top level bodies of modules
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1031:15)
at Module._compile (node:internal/modules/cjs/loader:1065:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
切换自
children.files.forEach(element => { ... })
至:
for (let element of children.files) { ...}
并且,改变这个:
recursive(driveService, element.id, folderID);
对此:
await recursive(driveService, element.id, folderID);
您想切换 .forEach()
,这样您就不会创建新的函数作用域,这样您就可以使用 await
,这样 await
就会暂停父函数。 .forEach()
回调中的新函数未声明 [=18=] 这就是您收到错误的原因(您不能在该回调函数中使用 await
)。并且,将该回调声明为 async
将使错误消失,但不会执行您想要的操作,因为它不会暂停父函数。
.forEach()
不 async/await 知道。不要在这种情况下使用它。
我什至可以说 .forEach()
现在已经过时了。由于 for/of
和 let/const
是块范围的并且 .forEach()
不支持 async/await
有很多理由避免 .forEach()
并且没有理由使用它。
您需要 await recursive(...)
以便将新的 promise 链绑定到当前的 promise 链,而不是创建一个全新的独立 promise 链,调用者不知道它何时完成。