简体   繁体   English

如何在 google-apps-script Web 应用程序的 for-loop 函数中将 async/await 与 FileReader 一起使用?

[英]How to use async/await with FileReader in for-loop function in google-apps-script web app?

I have created a Google Apps Script web application for uploading images to my Google Drive.我创建了一个 Google Apps Script Web 应用程序,用于将图像上传到我的 Google Drive。 It has a lot of rows, each row has an input tag for uploading file.它有很多行,每一行都有一个用于上传文件的输入标签。 I created an only one submit button to upload all chosen images in one time.我创建了一个只有一个提交按钮来一次性上传所有选择的图像。 However, I would like each row to upload each image in order and then delete that row when it was uploaded successfully in order as well.但是,我希望每一行按顺序上传每个图像,然后在成功上传后也按顺序删除该行。 The problem is I can't find the right way to use async/await function to upload the images to Drive with FileReader because when I run the script, It's still work as asynchronous function.问题是我找不到使用 async/await 函数将图像上传到带有 FileReader 的 Drive 的正确方法,因为当我运行脚本时,它仍然作为异步函数工作。

async function uploadImage() {
    var row   = document.getElementsByClassName('row');
    var file  = document.getElementsByClassName('img-file');
    var name  = document.getElementsByClassName('img-name');

    for (let i=0; i<row.length; i++) {
      var image = file[i].files[0];
      if (image) {
        var reader = new FileReader();
        reader.readAsDataURL(image);
        reader.onloadend = async (event) => { 
            await new Promise((resolve, reject) => { 
                google.script.run.withSuccessHandler(r => resolve())
                                 .uploadImgToDrive(name[i].value, event.target.result) 
            }).then(() => row[i].innerHTML='');
        }        
      }
    }    
}

If I understood what your goal is, the following code should work.如果我理解你的目标是什么,下面的代码应该可以工作。 Only one image at a time will be uploaded.一次只能上传一张图片。 Let me know if it fit your needs.让我知道它是否符合您的需求。

Please note that your function will always be asynchronous though because you have two asynchronous tasks inside it (FileReader and API call).请注意,您的函数将始终是异步的,因为其中有两个异步任务(FileReader 和 API 调用)。 The only thing you can decide is how many operations you want to handle "at the same time".您唯一可以决定的是您要“同时”处理多少个操作。

Finally, remember that anytime you use an async function it will immediately return an unresolved promise that will resolve with the value that the function returns when it finishes running.最后,请记住,无论何时您使用async函数,它都会立即返回一个未解析的承诺,该承诺将使用该函数完成运行时返回的值进行解析。

Inside async functions, await is used to "wait" for a promise to resolve before continuing (in this case, the promise that you are creating with new Promise() ), so it is similar to using .then() directly on the promise (you don't need both, that is why I removed the .then() part).async函数中, await用于在继续之前“等待”解决承诺(在这种情况下,您使用new Promise()创建的new Promise() ),因此它类似于直接在承诺上使用.then() (您不需要两者,这就是我删除.then()部分的原因)。


function uploadImages() {

    var row   = document.getElementsByClassName('row');
    var file  = document.getElementsByClassName('img-file');
    var name  = document.getElementsByClassName('img-name');

    (function nextImg(i) {
        var image = file[i].files[0];
        if (image) {
            var reader = new FileReader();
            reader.readAsDataURL(image);
            reader.onloadend = async (event) => {
                await new Promise((resolve, reject) => {
                    google.script.run.withSuccessHandler(r => resolve())
                        .uploadImgToDrive(name[i].value, event.target.result);
                });
                row[i].innerHTML='';
                if (i < row.length - 1) {
                  nextImg(i + 1);
                }
            };
        }
    })(0);

}

Optimised version (not tested):优化版本(未测试):

Avoids using innerHTML (important) and tries to reuse FileReader() instance (not sure if it will work).避免使用innerHTML (重要)并尝试重用FileReader()实例(不确定它是否有效)。


function uploadImages() {

    let row   = document.getElementsByClassName('row');
    let file  = document.getElementsByClassName('img-file');
    let name  = document.getElementsByClassName('img-name');

    let reader = new FileReader();

    (function nextImg(i) {
        if (file[i].files[0]) {
            reader.onloadend = async function onloadend(e) {
                await new Promise((resolve) => {
                    google.script.run.withSuccessHandler(r => resolve(r)).uploadImgToDrive(name[i].value, e.target.result);
                });
                while (row[i].firstChild) {
                    row[i].removeChild(row[i].firstChild);
                }
                if (i < row.length - 1) {
                    nextImg(i + 1);
                }
            };
            reader.readAsDataURL(file[i].files[0]);
        }
    })(0);

}

Another way to do this would be to hook up the loadend event of reader to a new promise and chain it:另一种方法是将readerloadend事件连接到一个新的 promise 并将其链接起来:

async function uploadImage() {
    var row   = document.getElementsByClassName('row');
    var file  = document.getElementsByClassName('img-file');
    var name  = document.getElementsByClassName('img-name');

    for (let i=0; i<row.length; i++) {
      var image = file[i].files[0];
      if (image) {
        var reader = new FileReader();
        reader.readAsDataURL(image);
        let promiseOfAllDone = new Promise(res=>reader.addEventListener('loadend',res))
            .then(event=>new Promise((resolve, reject) => { 
                    google.script.run.withSuccessHandler(resolve)
                                 .uploadImgToDrive(name[i].value, event.target.result)
             }).then(() => row[i].innerHTML='')
            .catch(e=>console.error(e));
        await promiseOfAllDone;//wait for all promises to be fulfilled
       }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM