【问题标题】:Firebase Function Returns Before All Callback functions complete executionFirebase 函数在所有回调函数完成执行之前返回
【发布时间】:2021-08-02 14:14:54
【问题描述】:

我正在使用 Google Storage NodeJS 客户端库来列出 GCS 存储桶路径。

这是 Firebase 函数的代码:

import * as functions from 'firebase-functions';
import { Storage } from '@google-cloud/storage';
import { globVars } from '../admin/admin';

const projectId = process.env.GCLOUD_PROJECT;
// shared global variables setup
const { keyFilename } = globVars;
// Storage set up
const storage = new Storage({
  projectId,
  keyFilename,
});

export const gcsListPath = functions
  .region('europe-west2')
  .runWith({ timeoutSeconds: 540, memory: '256MB' })
  .https.onCall(async (data, context) => {
    if (context.auth?.token.email_verified) {
      const { bucketName, prefix, pathList = false, fileList = false } = data;
      let list;
      const options = {
        autoPaginate: false,
        delimiter: '',
        prefix,
      };

      if (pathList) {
        options.delimiter = '/';

        let test: any[] = [];
        const callback =  (_err: any, _files: any, nextQuery: any, apiResponse: any) => {
          test = test.concat(apiResponse.prefixes);
          console.log('test : ', test);
          console.log('nextQuery : ', nextQuery);
          if (nextQuery) {
            storage.bucket(bucketName).getFiles(nextQuery, callback);
          } else {
            // prefixes = The finished array of prefixes.
            list = test;
          }
        }
       storage.bucket(bucketName).getFiles(options, callback);
      }

      if (fileList) {
        const [files] = await storage
          .bucket(bucketName)
          .getFiles(options);
        list = files.map((file) => file.name);
        
      }

      return { list }; //returning null as it exec before callback fns finish

    } else {
      return {
        error: { message: 'Bad Request', status: 'INVALID_ARGUMENT' },
      };
    }
  });

我的问题是我的 Firebase 函数在所有回调函数完成执行之前返回列表(null)。

有人可以指出并指出需要更改/添加什么以使函数等待所有回调函数完成。我已尝试添加 async/await,但似乎无法正确处理。

【问题讨论】:

    标签: async-await google-cloud-functions google-cloud-storage google-api-nodejs-client asynccallback


    【解决方案1】:

    您的错误原因是您使用了callback。它不在代码中等待。我建议将callback 代码变成一个承诺。像这样。

    import * as functions from "firebase-functions";
    import { Storage } from "@google-cloud/storage";
    import { globVars } from "../admin/admin";
    
    const projectId = process.env.GCLOUD_PROJECT;
    // shared global variables setup
    const { keyFilename } = globVars;
    // Storage set up
    const storage = new Storage({
      projectId,
      keyFilename,
    });
    
    const getList = (bucketName, options) => {
      return new Promise((resolve, reject) => {
        let list;
        let test: any[] = [];
        const callback = (
          _err: any,
          _files: any,
          nextQuery: any,
          apiResponse: any
        ) => {
          test = test.concat(apiResponse.prefixes);
          console.log("test : ", test);
          console.log("nextQuery : ", nextQuery);
          if (nextQuery) {
            storage.bucket(bucketName).getFiles(nextQuery, callback);
          } else {
            // prefixes = The finished array of prefixes.
            list = test;
          }
    
          resolve(list);
        };
    
        try {
          storage.bucket(bucketName).getFiles(options, callback);
        } catch (error) {
          reject(eror);
        }
      });
    };
    
    export const gcsListPath = functions
      .region("europe-west2")
      .runWith({ timeoutSeconds: 540, memory: "256MB" })
      .https.onCall(async (data, context) => {
        if (context.auth?.token.email_verified) {
          const { bucketName, prefix, pathList = false, fileList = false } = data;
          let list;
          const options = {
            autoPaginate: false,
            delimiter: "",
            prefix,
          };
    
          if (pathList) {
            options.delimiter = "/";
    
            list = await getList(bucketName, options);
          }
    
          if (fileList) {
            const [files] = await storage.bucket(bucketName).getFiles(options);
            list = files.map((file) => file.name);
          }
    
          return { list }; //returning null as it exec before callback fns finish
        } else {
          return {
            error: { message: "Bad Request", status: "INVALID_ARGUMENT" },
          };
        }
      });
    
    

    我不确定fileList 的部分是否会按预期工作。看起来 API 不支持等待,只支持回调。

    【讨论】:

    • 这非常有用并且有效。我只需要将 resolve(list) 移到 else 块中。我将在答案中发布更新的代码
    【解决方案2】:
    import * as functions from "firebase-functions";
    import { GetFilesOptions, Storage } from "@google-cloud/storage";
    import { globVars } from "../admin/admin";
    
    const projectId = process.env.GCLOUD_PROJECT;
    // shared global variables setup
    const { keyFilename } = globVars;
    // Storage set up
    const storage = new Storage({
      projectId,
      keyFilename,
    });
    
    const getList = (bucketName: string, options: GetFilesOptions) => {
      return new Promise((resolve, reject) => {
        // let test: any[] = [];
        let list: any[] = [];
        const callback = (
          _err: any,
          _files: any,
          nextQuery: any,
          apiResponse: any
        ) => {
          list = list.concat(apiResponse.prefixes);
          console.log("list : ", list);
          console.log("nextQuery : ", nextQuery);
          if (nextQuery) {
            storage.bucket(bucketName).getFiles(nextQuery, callback);
          } else {
            // prefixes = The finished array of prefixes.
            resolve(list);
          }
    
        };
    
        try {
          storage.bucket(bucketName).getFiles(options, callback);
        } catch (error) {
          reject(error);
        }
      });
    };
    
    export const gcsListPath = functions
      .region("europe-west2")
      .runWith({ timeoutSeconds: 540, memory: "256MB" })
      .https.onCall(async (data, context) => {
        if (context.auth?.token.email_verified) {
          const { bucketName, prefix, pathList = false, fileList = false } = data;
          let list;
          const options = {
            autoPaginate: false,
            delimiter: "",
            prefix,
          };
    
          if (pathList) {
            options.delimiter = "/";
    
            list = await getList(bucketName, options);
          }
    
          if (fileList) {
            const [files] = await storage.bucket(bucketName).getFiles(options);
            list = files.map((file) => file.name);
          }
    
          return { list }; //returning null as it exec before callback fns finish
        } else {
          return {
            error: { message: "Bad Request", status: "INVALID_ARGUMENT" },
          };
        }
      });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 2015-02-17
      • 2018-02-08
      • 2018-08-12
      • 2014-08-25
      • 1970-01-01
      • 2017-05-17
      相关资源
      最近更新 更多