链接两个异步操作以使成功或失败同时进行(移动文件+数据库保存)

时间:2019-07-18 10:49:05

标签: javascript node.js database callback filesystems

我有两个带有回调的异步操作。我想确保它们都成功或失败,但不能确保一个成功一个失败。这两个动作可能应该像是一个可以退回的过程?

我们来说明一下:

// In this simplified code, i assume i uploaded a file in a temporary folder.
// Every validations passed and now the goal is to move the file from temporary folder to final destination folder and to save it into database.
// This 'move' and this 'save' are my two async actions with a callback when each action is completed.
// Maybe i am not using the right way / pattern to do it, thank you for enlightening me if necessary.

myController.create = function (req, res, next) {

    // I move the file from oldPath (temp directory) to newPath (final destination)
    mv(oldPath, newPath, function (err) {

        // If err, file is not moved i stop here, went fine. The temp directory is cleared later by the system every X period of time.
        if (err) { return next(err); }

        var file = new FileModel({
          // some properties (name, path...)    
        });

        // The file is now moved, need to save it into database
        file.save(function (err) {

            if (!err) { return next(); } // everything went fine

            // If err, nothing stored in database but the file is still in final folder :o
            // I could unlink the file but it still can fail and keep my file inside destination folder with no database entry.
            fs.unlink(new_path, function (other_err) {
                if (other_err) { return next(other_err); } 
                return next(err);
            }

        });

    });

};

在上面的代码中,如果第一个动作成功,则无法保证第二个动作也将成功,并且如果失败,我可以还原(第一个动作)。这两个动作是独立的,而不是相互链接/配对和协同工作。

如果文件移动成功,则数据库中的保存也应该成功。如果无法成功保存到数据库中,那么我应该恢复到temp目录或从目标文件夹中删除该文件,以使其与数据库足够。换句话说,如果第二项操作失败,则第一个操作应失败两次。

实现此目标的好方法是什么?

编辑:我可以看到的一个解决方案是,每隔X个时间段检查最终目标文件夹中的每个文件是否在db中都有一个条目,如果没有,则删除它。

1 个答案:

答案 0 :(得分:0)

您需要使用promise来实现这种事情,例如,您需要创建一个用户然后发送通知。因此这两个动作都是异步的,需要一个接一个地完成。

const user = {};

// This function create user and send back a id
user.createUser = (data) => {
  return new Promise((resolve, reject) => {
    // ...you callbacks
    if (some conditions are true) {
    return resolve(id);
  } else {
    return reject();
  }
});
};

// This function finds user detail by id and send notifiaction
user.sendNotification = (id) => {
  return new Promise((resolve, reject) => {
    // ...you callbacks
    return resolve();
  });
};

user.action = async () => {
  try {
    const userId = await user.createUser(); // Wait for promise to resolve
    await user.sendNotification(userId);
    return true;
  } catch (err) {
    throw err;
  }
};

module.exports = user;

在上面的代码中,您可以看到user.action()函数一个接一个地调用2个单独的函数,async/await仅适用于promise,因此我们使用关键字{ {1}}。因此,简而言之,您需要使用promise来处理这类事情。

我希望它会有所帮助。快乐编码:)