Busboy 在解析所有数据之前完成

Dog*_*cil 1 node.js express busboy

我有一个快速应用程序,并且有一个使用busboy 解析表单数据的函数,该数据返回表单的字段值,但在返回调用之前不解析整个字段。


module.exports = async function (headers, invalidMime, res ,req) {
    let fields = {};
    const fileWrites = []
    let filesToUpload = [];
    let finished = false;
    const busboy = new Busboy({
        headers: headers,
        limits: { ileSize: 10 * 1024 * 1024 }
    });

    await busboy.on("field", (fieldname, val) => {
        console.log(fieldname); // Log 1
        fields[fieldname] = val;
    });

    await busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
        
        if (invalidMime(mimetype)) return res.status(404).json({ [fieldname]: "Wrong file type submitted" });
        
        file.on("limit", () => { return res.status(404).json({ general: "File size too large!" }); });

        const randomizedFileName = createFileName(filename);
        const filePath = path.join(os.tmpdir(), randomizedFileName);

        fileWrites.push(createImagePromise(file, filePath, randomizedFileName, mimetype, fieldname));
    });

    busboy.on("finish", () => {
      console.log(fields); // Log 2
    });
      
    busboy.end(req.rawBody);

    return {filesToUpload: fileWrites, fields: fields}
}
Run Code Online (Sandbox Code Playgroud)

这会返回我的字段,但缺少最后一个字段。当我使用控制台日志对其进行调试时,我可以看到在busboy.on("finish")返回值后执行,这会导致变量丢失。

const formData = await  FormParser(req.headers, invalidMime, res, req);

console.log(formData); // Log 3
const { fields, filesToUpload } = formData;

Run Code Online (Sandbox Code Playgroud)
  var1                     // Log 1 - Before return
  var2                     // Log 1 - Before return
  var3                     // log 1 - Before return
  { filesToUpload: [],     // Log 3 - After return
    fields:
     { var1: 'var1',
       var2: 'var2',
       var3: 'var3' } }          
  var4                     // Log 1 - After return
  { var1: 'var1',          // Log 2 - After return
    var2: 'var2',
    var3: 'var3',
    var4: 'var4' }                

Run Code Online (Sandbox Code Playgroud)

如何让 Busboy 在解析完成后返回值?

Tom*_*lak 5

await当您到处撒上一些 s 时,异步函数不会神奇地变成同步函数。

例如,这是没有意义的:

await busboy.on("field", (fieldname, val) => {
    console.log(fieldname); // Log 1
    fields[fieldname] = val;
});
Run Code Online (Sandbox Code Playgroud)

你认为它以某种方式等待fields对象被填充,但它真正做的是:它等待.on()函数返回,并且这个函数立即返回。它唯一的工作是分配一个事件处理程序。该field事件甚至还没有发生。

异步编程的解决方案始终是:在事件处理程序中执行表明任务已完成的工作。您试图return {filesToUpload: fileWrites, fields: fields}在函数的最后一行中完成工作 ( ) ,就好像最后一行是最后运行的事情一样。事实并非如此。

一旦您移动了事件处理程序中需要对事件做出反应的位,您就会发现整个函数根本不需要这样做async

免责声明:以下代码未经测试,我以前没有使用过busboy,按照它的意思做,不一定按照它说的做。

module.exports = function (headers, invalidMime, res, req) {
    let fields = {};
    let pendingFileWrites = [];

    const busboy = new Busboy({
        headers: headers,
        limits: { fileSize: 10 * 1024 * 1024 }
    });

    busboy.on("filesLimit", () => {
        res.status(400).json({ error: "File size too large!" });
    });
    busboy.on("error", () => {
        res.status(500).json({ error: "Error parsing data" });
    });
    busboy.on("field", (fieldname, val) => {
        fields[fieldname] = val;
    });
    busboy.on("finish", () => {
        Promise.all(pendingFileWrites).then((fileWrites) => {
            // NOW we're done
            res.json({
                filesToUpload: fileWrites, 
                fields: fields
            });
        });
    });

    busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
        console.log(`Processing [{filename}] ({mimetype})`);
        if (invalidMime(mimetype)) return res.status(404).json({ [fieldname]: "Wrong file type submitted" });
        file.on("limit", () => { return res.status(404).json({ general: "File size too large!" }); });
        file.on("end", () => { console.log(`Done processing [{filename}] ({mimetype})`); });

        const randomizedFileName = createFileName(filename);
        const filePath = path.join(os.tmpdir(), randomizedFileName);

        pendingFileWrites.push(createImagePromise(file, filePath, randomizedFileName, mimetype, fieldname));
    });
};
Run Code Online (Sandbox Code Playgroud)

请注意,您可以这样做async

busboy.on("finish", () => {
    Promise.all(pendingFileWrites).then((fileWrites) => {
        // NOW we're done
        res.json({
            filesToUpload: fileWrites, 
            fields: fields
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

喜欢

busboy.on("finish", async () => {
    var fileWrites = await Promise.all(pendingFileWrites);
    // NOW we're done
    res.json({
        filesToUpload: fileWrites, 
        fields: fields
    });
});
Run Code Online (Sandbox Code Playgroud)

甚至

busboy.on("finish", async () => {
    res.json({
        filesToUpload: await Promise.all(pendingFileWrites), 
        fields: fields
    });
});
Run Code Online (Sandbox Code Playgroud)

如果你愿意的话。无论哪种情况,您都需要添加错误处理(前者通过.catch(),后者通过try/catch块)。