Javascript Firebase云功能太慢

Javascript Firebase云功能太慢,javascript,firebase,google-cloud-platform,google-cloud-firestore,google-cloud-functions,Javascript,Firebase,Google Cloud Platform,Google Cloud Firestore,Google Cloud Functions,我有一个云函数,它接收图像的uid,并将其与用户关联,用户在验证其尺寸并生成其缩略图后调用它。它看起来很简单,但我必须等待大约40秒才能看到结果,有时它会变得拥挤或其他什么,我必须再次调用该函数才能看到以前的结果 以前有人经历过吗?我怎样才能解决这个问题 exports.validateImageDimensions = functions .region("us-central1") .runWith({ memory: "2GB", timeo

我有一个云函数,它接收图像的uid,并将其与用户关联,用户在验证其尺寸并生成其缩略图后调用它。它看起来很简单,但我必须等待大约40秒才能看到结果,有时它会变得拥挤或其他什么,我必须再次调用该函数才能看到以前的结果

以前有人经历过吗?我怎样才能解决这个问题

exports.validateImageDimensions = functions
  .region("us-central1")
  .runWith({ memory: "2GB", timeoutSeconds: 120 })
  .https.onCall(async (data, context) => {
正如你所看到的,CPU使用率很高

谢谢

更新 功能代码:

exports.validateImageDimensions = functions
  .region("us-central1")
  .runWith({ memory: "2GB", timeoutSeconds: 120 })
  .https.onCall(async (data, context) => {
    // Libraries
    const admin = require("firebase-admin");
    const sizeOf = require("image-size");
    const url = require("url");
    const https = require("https");
    const sharp = require("sharp");
    const path = require("path");
    const os = require("os");
    const fs = require("fs");

    // Lazy initialization of the Admin SDK
    if (!is_validateImageDimensions_initialized) {
      admin.initializeApp();
      is_validateImageDimensions_initialized = true;
    }

    // Create Storage
    const storage = admin.storage();

    // Create Firestore
    const firestore = admin.firestore();

    // Get the image's owner
    const owner = context.auth.token.uid;

    // Get the image's info
    const { id, description, location, tags } = data;

    // Photos's bucket
    const bucket = storage.bucket("bucket");

    // File Path
    const filePath = `photos/${id}`;

    // Get the file
    const file = getFile(filePath);

    // Check if the file is a jpeg image
    const metadata = await file.getMetadata();
    const isJpgImage = metadata[0].contentType === "image/jpeg";

    // Get the file's url
    const fileUrl = await getUrl(file);

    // Get the photo dimensions using the `image-size` library
    https.get(url.parse(fileUrl), (response) => {
      let chunks = [];
      response
        .on("data", (chunk) => {
          chunks.push(chunk);
        })
        .on("end", async () => {
          // Check if the image has valid dimensions
          let dimensions = sizeOf(Buffer.concat(chunks));

          // Create the associated Firestore's document to the valid images
          if (isJpgImage && hasValidDimensions(dimensions)) {
            // Create a thumbnail for the uploaded image
            const thumbnailPath = await generateThumbnail(filePath);

            // Get the thumbnail
            const thumbnail = getFile(thumbnailPath);

            // Get the thumbnail's url
            const thumbnailUrl = await getUrl(thumbnail);

            try {
              await firestore
                .collection("posts")
                .doc(owner)
                .collection("userPosts")
                .add({
                  id,
                  uri: fileUrl,
                  thumbnailUri: thumbnailUrl, // Useful for progress images
                  description,
                  location,
                  tags,
                  date: admin.firestore.FieldValue.serverTimestamp(),
                  likes: [], // At the first time, when a post is created, zero users has liked it
                  comments: [], // Also, there aren't any comments
                  width: dimensions.width,
                  height: dimensions.height,
                });

              // TODO: Analytics posts counter
            } catch (err) {
              console.error(
                `Error creating the document in 'posts/{owner}/userPosts/' where 'id === ${id}': ${err}`
              );
            }
          } else {
            // Remove the files that are not jpeg images, or whose dimensions are not valid
            try {
              await file.delete();

              console.log(
                `The image '${id}' has been deleted because it has invalid dimensions.
                 This may be an attempt to break the security of the app made by the user '${owner}'`
              );
            } catch (err) {
              console.error(`Error deleting invalid file '${id}': ${err}`);
            }
          }
        });
    });

    /* ---------------- AUXILIAR FUNCTIONS  ---------------- */

    function getFile(filePath) {
      /* Get a file from the storage bucket */

      return bucket.file(filePath);
    }

    async function getUrl(file) {
      /* Get the public url of a file  */

      const signedUrls = await file.getSignedUrl({
        action: "read",
        expires: "01-01-2100",
      });

      // signedUrls[0] contains the file's public URL
      return signedUrls[0];
    }

    function hasValidDimensions(dimensions) {
      // Posts' valid dimensions
      const validDimensions = [
        {
          width: 1080,
          height: 1080,
        },
        {
          width: 1080,
          height: 1350,
        },
        {
          width: 1080,
          height: 750,
        },
      ];

      return (
        validDimensions.find(
          ({ width, height }) =>
            width === dimensions.width && height === dimensions.height
        ) !== undefined
      );
    }

    async function generateThumbnail(filePath) {
      /* Generate thumbnail for the progressive images */

      // Download file from bucket
      const fileName = filePath.split("/").pop();
      const tempFilePath = path.join(os.tmpdir(), fileName);

      const thumbnailPath = await bucket
        .file(filePath)
        .download({
          destination: tempFilePath,
        })
        .then(() => {
          // Generate a thumbnail using Sharp
          const size = 50;
          const newFileName = `${fileName}_${size}_thumb.jpg`;
          const newFilePath = `thumbnails/${newFileName}`;
          const newFileTemp = path.join(os.tmpdir(), newFileName);
          sharp(tempFilePath)
            .resize(size, null)
            .toFile(newFileTemp, async (_err, info) => {
              // Uploading the thumbnail.
              await bucket.upload(newFileTemp, {
                destination: newFilePath,
              });

              // Once the thumbnail has been uploaded delete the temporal file to free up disk space.
              fs.unlinkSync(tempFilePath);
            });

          // Return the thumbnail's path
          return newFilePath;
        });

      return thumbnailPath;
    }
  });
Pd:在控制台中,我可以读取以下记录:

"Function execution took 103 ms, finished with status code: 200"

但是,正如我之前所说,我必须等待大约40秒,才能在我的firestore上看到新的文档

您没有正确处理承诺。可调用函数必须返回以下承诺:

  • 在所有异步工作完成时解析
  • 解析要发送回客户端的数据
  • 现在,您的函数不返回任何内容,因此它会立即返回给调用方,并且您启动的异步工作的未来是不确定的


    请注意,它是异步的,并在调用其回调之前立即返回。您需要找到一种方法来返回一个承诺,当回调的所有工作都完成时,该承诺就会得到解决。(考虑到还有其他HTTP客户机库,它们可以更容易地获得承诺,而不必处理回调。)

    如果不了解实际功能,很难回答您的问题,可能它的效率不高,导致等待时间长。另外,您的云函数使用2GB的RAM运行,而不是CPU。我在函数配置中看到,如果我设置更高的RAM,函数也会有更多的CPU。@是的,我已经用完整的代码更新了这个问题。可能这与firestore中的一些延迟有关。如果您使用硬编码的值创建测试对象,是否也需要40秒才能显示?您已经发现问题在于:https.get(url.parse(fileUrl),(response)=>{let chunks=[];response.on(“data”,(chunk)=>{chunks.push(chunk);})。on(“end”,async()=>{….如果我将之前的图像关联上传到firestore,我可以在1秒内看到结果。我应该返回void吗?我的意思是,在客户端,我不希望从函数得到响应,我使用了https.onCall,因为我认为这是一种从应用程序调用云函数的方法。无论客户端是否希望得到响应您需要发送一个。HTTP就是这样工作的。返回一个承诺,该承诺与要发送的数据或至少一些伪数据(如空对象)进行解析。该承诺必须在所有异步工作完全完成后才能解析,否则异步工作将不会按您期望的方式运行。伙计,您是一个天才,只需完全按照您所说的去做,并获得正确的结果即可在一秒钟内得到结果。非常感谢!希望有一天能像你一样专业地使用javascript:D