代码之家  ›  专栏  ›  技术社区  ›  Sam Munroe

javascript承诺不按顺序启动

  •  1
  • Sam Munroe  · 技术社区  · 6 年前

    我一直在努力有效地管理如何在express.js应用程序中实现我的承诺。

    现在我有以下场景:在注册过程中,用户有一个可选的 Organization Name 字段。如果这是填写的,我需要创建 Organization 对象,然后添加 _id 我正在申请的其他信息 user 是的。如果没有 Organization name ,继续并更新基本 用户 信息。

    <--现在 用户 正在更新之前 organization 正在创建。-->

    //basic info passed from the signup form
    info['first_name'] = req.body.first_name;
    info['last_name'] = req.body.last_name;
    info['flags.new_user'] = false;
    
    //if organization name is passed, create object and store _id in user object. 
    let create_organization = new Promise(function(resolve, reject) {
      if (req.body.organization_name !== "") { //check if name is sent from form
        Organization.create({
          name: req.body.organization_name
        }, function(err, result) {
          console.log(result);
          if (!err) {
            info['local.organization'] = result._id;
            resolve()
          } else {
            reject()
          }
        })
      } else {
        resolve()
      }
    });
    
    let update_user = new Promise(function(resolve, reject) {
      User.update({
        _id: req.user._id
      }, info, function(err, result) {
        if (!err) {
          console.log("Updated User!"); < --prints before Organization is created
          resolve();
        } else {
          reject();
        }
      })
    });
    
    create_organization
      .then(function() {
        return update_user;
      })
      .then(function() {
        res.redirect('/dash');
      })
    
    2 回复  |  直到 6 年前
        1
  •  4
  •   T.J. Crowder    6 年前

    在开始后续工作之前,代码中的任何内容都不会等待第一个承诺完成。你一打电话工作就开始了 User.update ,当您调用 new Promise 在承诺执行人身上有密码。

    相反,要等到上一个承诺得到解决。我可以通过将这些函数包装在可重用的、支持承诺的包装器中来实现( createOrganization updateUser )以下内容:

    // Reusable promise-enabled wrappers
    function createOrganization(name) {
        return new Promise(function(resolve, reject) {
            Organization.create({name: name}, function(err, result) {
                console.log(result);
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            });
        });
    }
    
    function updateUser(id, info) {
        return new Promise(function(resolve, reject) {
            User.update({_id: id}, info, function(err, result) {
                if (err) {
                    reject(err);
                } else {
                    resolve();
                }
            })
        });
    }
    

    (您可以使用 util.promisify 或者 promisify npm 模块以避免手动执行此操作。)

    然后:

    //basic info passed from the signup form
    info['first_name'] = req.body.first_name;
    info['last_name'] = req.body.last_name;
    info['flags.new_user'] = false;
    
    //if organization name is passed, create object and store _id in user object. 
    (req.body.organization_name === "" ? Promise.resolve() : createOrganization(req.body.organization_name))
    .then(function() {
        return updateUser(req.user._id, info);
    })
    .catch(function(error) {
        // handle/report error
    });
    

    (我坚持使用ES5级语法,因为您的代码似乎在这样做…)

        2
  •  1
  •   raina77ow    6 年前

    请看,所谓的“executor函数”,传递到promise构造函数中,是 invoked immediately 是的。这就是为什么在两个远程过程调用之间存在竞争条件。要解决此问题,请让更新负责承诺的创建:

    function updateUser(userId, userInfo) {
      return new Promise(function(resolve, reject) {
        User.update({_id: userId}, userInfo, function(err, result) {
          if (err) { 
            reject(err);
          }
          else {
            resolve(result);
          }
        });
      });
    }
    

    …调用这个函数 then() 是的。通过这样做,只有在 updateUser 被调用-之后 createOrganization() 完成了任务。