首页 > 解决方案 > 链接两个异步操作以使两者一起成功或失败(移动文件+数据库保存)

问题描述

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

让我们说明一下:

// 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);
            }

        });

    });

};

在上面的代码中,如果第一个操作成功,则无法保证我的第二个操作也会成功,并且如果失败,我可以恢复(我的第一个操作)。这两个动作是分开和独立的,而不是链接/配对并一起工作。

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

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

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

标签: javascriptnode.jsdatabasecallbackfilesystems

解决方案


你需要使用 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 起作用,所以我们让函数 Promisify 并使用关键字 一次性使用await。因此,简而言之,您需要使用 Promise 来处理此类事情。

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


推荐阅读