1

The code works and uploads images to Backblaze but it's not waiting for the for loop to finish running and the query to finish before calling next. If I console log the file ids it will list the ids 3 or four seconds after next() has been called!

import fs from "fs";
import B2 from "backblaze-b2";
import path from "path";
import dotenv from "dotenv";

dotenv.config();

export const uploadToBackBlaze = async (req, res, next) => {
    console.log("I'm here uploading to Backblaze");

    const b2 = new B2({
        applicationKeyId: process.env.BACKBLAZE_ACCOUNT_ID,
        applicationKey: process.env.BACKBLAZE_MASTER_APPLICATION_ID,
    });

    const __dirname = path.resolve();
    let tempDir = path.join(__dirname, "chapterTemp");

    const imageIds = [];
    try {
        b2.authorize()
            .then(async () => {
                const bucketId = process.env.BACKBLAZE_BUCKET_ID;

                fs.readdir(tempDir, async function (err, files) {
                    if (err) {
                        console.error(err);
                        res.sendStatus(500).json({ message: err.message });
                        return;
                    }
                    for (const file of files) {
                        const fileData = fs.readFileSync(path.join(tempDir, file));
                        const uploadFileName = path.join(file);
                        const uploadUrl = await b2.getUploadUrl(bucketId);
                        const response = await b2.uploadFile({
                            uploadUrl: uploadUrl.data.uploadUrl,
                            uploadAuthToken: uploadUrl.data.authorizationToken,
                            filename: uploadFileName,
                            data: fileData,
                            mime: "image/png" || "image/jpg" || "image/jpeg" || "image/webp", // replace with the appropriate MIME type for your files
                        });
                        console.log(response.data.fileId);
                        imageIds.push(response.data.fileId);
                    }
                });
            })
            .then(() => {
                console.log(imageIds);
                req.imageIds = imageIds;
                next();
            });
    } catch (error) {
        console.log(error);
        return res.status(500).json({ message: error.message });
    }
};

I want it to finish waiting for the for loop and push the ids into the array before calling next, that way I can store the Ids in the database!

metadaddy
  • 4,234
  • 1
  • 22
  • 46
  • 1
    You are mixing plain callback async operations like `fs.readdir()` with promise operations. They are not compatible. Use `let files = await fs.promises.readdir(...)` instead to get rid of that callback. Also, why mix `.then()` and `await`. That just makes the code more confusing to write and understand. You can replace ALL your `.then()` with `await` and the code will be much simpler. – jfriend00 Apr 02 '23 at 04:27

1 Answers1

0

The root cause of your problem is that, as @jfriend00 says in a comment, fs.readdir() is a plain callback async function. Therefore, execution proceeds to the then() containing next() while fs.readdir() is still running. As @jfriend00 also mentions, mixing then() and await makes the code more complex and difficult to write correctly.

Here's a version that works. It uses fs.readdirSync(), which simply returns the array of files, and replaces then() with await to make the code easier to understand.

import fs from "fs";
import B2 from "backblaze-b2";
import path from "path";
import dotenv from "dotenv";

dotenv.config();

export const uploadToBackBlaze = async (req, res, next) => {
  console.log("I'm here uploading to Backblaze");

  const b2 = new B2({
    applicationKeyId: process.env.BACKBLAZE_ACCOUNT_ID,
    applicationKey: process.env.BACKBLAZE_MASTER_APPLICATION_ID,
  });

  const __dirname = path.resolve();
  let tempDir = path.join(__dirname, "chapterTemp");

  const imageIds = [];
  try {
    await b2.authorize();

    const bucketId = process.env.BACKBLAZE_BUCKET_ID;

    const files = fs.readdirSync(tempDir);
    for (const file of files) {
      const fileData = fs.readFileSync(path.join(tempDir, file));
      const uploadFileName = path.join(file);
      const uploadUrl = await b2.getUploadUrl(bucketId);
      const response = await b2.uploadFile({
        uploadUrl: uploadUrl.data.uploadUrl,
        uploadAuthToken: uploadUrl.data.authorizationToken,
        filename: uploadFileName,
        data: fileData,
        mime: "image/png" || "image/jpg" || "image/jpeg" || "image/webp", // replace with the appropriate MIME type for your files
      });
      console.log(response.data.fileId);
      imageIds.push(response.data.fileId);
    }

    console.log(imageIds);
    req.imageIds = imageIds;
    next();
  } catch (error) {
    console.log(error);
    return res.status(500).json({ message: error.message });
  }
};

Output:

I'm here uploading to Backblaze
4_z0145cfc9e3f5ec0f74ed0c1b_f117d3fad62e89e20_d20230402_m183653_c004_v0402012_t0031_u01680460613262
4_z0145cfc9e3f5ec0f74ed0c1b_f106c056c78a74bfd_d20230402_m183653_c004_v0402006_t0016_u01680460613601
4_z0145cfc9e3f5ec0f74ed0c1b_f10983156bddd6e1d_d20230402_m183654_c004_v0402001_t0002_u01680460614026
4_z0145cfc9e3f5ec0f74ed0c1b_f110cce66726eafc9_d20230402_m183654_c004_v0402002_t0004_u01680460614244
4_z0145cfc9e3f5ec0f74ed0c1b_f11877e4fecf8da12_d20230402_m183654_c004_v0402012_t0026_u01680460614505
4_z0145cfc9e3f5ec0f74ed0c1b_f107e976b612ad7d0_d20230402_m183654_c004_v0402005_t0057_u01680460614840
[
  '4_z0145cfc9e3f5ec0f74ed0c1b_f117d3fad62e89e20_d20230402_m183653_c004_v0402012_t0031_u01680460613262',
  '4_z0145cfc9e3f5ec0f74ed0c1b_f106c056c78a74bfd_d20230402_m183653_c004_v0402006_t0016_u01680460613601',
  '4_z0145cfc9e3f5ec0f74ed0c1b_f10983156bddd6e1d_d20230402_m183654_c004_v0402001_t0002_u01680460614026',
  '4_z0145cfc9e3f5ec0f74ed0c1b_f110cce66726eafc9_d20230402_m183654_c004_v0402002_t0004_u01680460614244',
  '4_z0145cfc9e3f5ec0f74ed0c1b_f11877e4fecf8da12_d20230402_m183654_c004_v0402012_t0026_u01680460614505',
  '4_z0145cfc9e3f5ec0f74ed0c1b_f107e976b612ad7d0_d20230402_m183654_c004_v0402005_t0057_u01680460614840'
]
metadaddy
  • 4,234
  • 1
  • 22
  • 46