未定义Node.js异步瀑布回调函数

时间:2018-11-19 08:14:00

标签: javascript node.js asynchronous waterfall

我正在尝试将文件及其详细信息保存在数据库中。

有两个调用的瀑布函数,但是第二个函数没有等待第一个函数完成。

即使不使用瀑布,每个系列也无法按预期工作。它不等待记录创建,因此由于相同的ID而发生唯一性错误。 我在这里做错什么,如何解决?

谢谢!

       async.eachSeries(uploadedPhotos, async function (uploadedFile, callback) {

          async.waterfall([
            async function() {
              var lastUser = await TblUserFiles.find({}).sort('id DESC').limit(1);
              // fileID remains undefined if i remove async-await from the  function 
              var fileID = lastUser[0].id;
              fileID += 1;
              cbb(null, fileID, uploadedFile);
            },
            async function(file_id, uploadedFile, cbb) {
              sails.log("save file id is " + file_id);
              sails.log("savee file id is " + uploadedFile['filename']);
              var today = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
              await TblUserFiles.findOrCreate({ customer_no: req.session.userId, file_type: 'profile_image' }, {
                id: fileID,
                customer_no: req.session.userId,
                file_name: uploadedFile['filename'],
                file_type: 'profile_image',
                is_approved: 'No',
                approved_by: 0,
                approved_on: today,
                approved_from: ip,
                uploaded_date: today,
                modified_date: today
              }).exec(async (err, user, wasCreated) => {
                if (err) { return res.serverError(err); }

                if (wasCreated) {
                  // created a new user
                  sails.log("new file was uploaded...")
                  return cbb(err, "done");

                  // return res.send("sent");
                }
                else {
                  // found existing user
                  var user = await TblUserFiles.create({
                    id: fileID,
                    customer_no: req.session.userId,
                    file_name: uploadedFile["filename"],
                    file_type: "image",
                    is_approved: "No",
                    approved_by: 0,
                    approved_on: today,
                    approved_from: ip,
                    uploaded_date: today,
                    modified_date: today
                  }).intercept(err => {
                    // Return a modified error here (or a special exit signal)
                    // and .create() will throw that instead
                    err.message = "Uh oh: " + err.message;
                    return err;
                  }).fetch();
                  if (user) {
                    sails.log("found existing files..")
                    return cbb(err, "done");
                  }
                  sails.log("this should not be called");
                }
              });
            }
          ], (err, success) => {
            if (err) sails.log(err);
            return callback(err, 'done')
          });



        }, function (err) {
          // if any of the saves produced an error, err would equal that error
          if (err) {
            sails.log(err);
          } else {
            return res.json({
              message: uploadedPhotos.length + ' file(s) uploaded successfully!',
              files: uploadedPhotos
            });
          }
        });

1 个答案:

答案 0 :(得分:2)

更新的答案:

我重写了代码。 我忘记了async.js以不同的方式处理promise。基本上,您不使用callback()。请改用return。如果发生错误,请使用throw new Error(message)。 有关更多信息,请参见here。阅读主题:使用ES2017异步功能

async.eachSeries(uploadedPhotos, async uploadedFile => {
  var lastUser = await TblUserFiles.find({}).sort('id DESC').limit(1);
  var fileID = lastUser[0].id;
  fileID += 1;
  sails.log("save file id is " + file_id);
  sails.log("savee file id is " + uploadedFile['filename']);
  var today = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
  await TblUserFiles.findOrCreate(
    { customer_no: req.session.userId, file_type: 'profile_image' },
    {
      id: fileID,
      customer_no: req.session.userId,
      file_name: uploadedFile['filename'],
      file_type: 'profile_image',
      is_approved: 'No',
      approved_by: 0,
      approved_on: today,
      approved_from: ip,
      uploaded_date: today,
      modified_date: today
    }
  ).exec(async (err, user, wasCreated) => {
    if (err) throw new Error(err);
    if (wasCreated) {
      sails.log("new file was uploaded...");
      return;
    } else {
      await TblUserFiles.create({
        id: fileID,
        customer_no: req.session.userId,
        file_name: uploadedFile["filename"],
        file_type: "image",
        is_approved: "No",
        approved_by: 0,
        approved_on: today,
        approved_from: ip,
        uploaded_date: today,
        modified_date: today
      })
      .intercept(err => {
        throw new Error("Uh oh: " + err.message);
      }).fetch();
      if (user) {
        sails.log("found existing files..");
        return;
      } else {
        sails.log("this should not be called");
        return;
      }
    }
  });
}, err => {
  // Don't call res.serverError() or res.json() inside the async loop!
  if (err) {
    sails.log(err);
    res.serverError(err);
  }
  else {
    res.json({
      message: uploadedPhotos.length + ' file(s) uploaded successfully!',
      files: uploadedPhotos
    });
  }
});

我认为这里的第一个问题是您忘记给第一个任务一个回调函数(在这种情况下为cbb)。

async.waterfall([
            async function(cbb) {
              var lastUser = await TblUserFiles.find({}).sort('id DESC').limit(1);
              // fileID remains undefined if i remove async-await from the  function 
              var fileID = lastUser[0].id;
              fileID += 1;
              cbb(null, fileID, uploadedFile);
            },
            async function(file_id, uploadedFile, cbb) {
...

第二,您不应返回回调。回调是功能而不是承诺。只需正常使用它们即可。


顺便说一句,const async = require('async');不会覆盖async关键字。编译器可以分辨出它们之间的区别。以下脚本示例证明了这一点:

const async = require('async');

let runPromise = (name, timer, success = true) => {
  console.log(`${name} starts.`);
  return new Promise((resolve, reject) => {
    if (success) {
      setTimeout(function () {
        resolve(`${name} finished after ${timer / 1000} seconds(resolved).`);
      }, timer);
    } else {
      reject(`${name} failed(rejected).`);
    }
  });
};

async function asyncFunction() {
  let txt = await runPromise('A', 1000);
  console.log(txt);
}

asyncFunction();