使用递归方法异步

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/oflet/const 是块范围的并且 .forEach() 不支持 async/await 有很多理由避免 .forEach() 并且没有理由使用它。


您需要 await recursive(...) 以便将新的 promise 链绑定到当前的 promise 链,而不是创建一个全新的独立 promise 链,调用者不知道它何时完成。