首页 文章

如何使用Q.js正确链接条件(?)promise

提问于
浏览
15

如果这是一个简单的误解,我还没有完全理解承诺,所以道歉 .

我有一个删除页面上的项目的功能,但我有一个特定的行为取决于页面的状态 . Psuedo代码方式是这样的:

Does the page have changes?
    If yes - prompt to save changes first
         If yes - save changes
         If no - exit function
    If no - continue
Prompt to confirm delete
    If yes - delete item and reload data
    If no - exit function

希望这是有道理的 . 基本上如果有变化,必须先保存数据 . 然后,如果数据已保存,或者如果没有开始更改,则提示用户确认删除 . 问题是我正在使用durandal和微风,我似乎无法将他们正确归还的承诺链接起来 .

我的功能目前看起来像这样,我知道这是错误的,但我正在努力找出解决问题的方法 .

if (this.hasChanges()) {
    app.showMessage('Changes must be saved before removing external accounts.  Would you like to save your changes now?', 'Unsaved Changes...', ['Yes', 'No'])
        .then(function (selectedOption) {
             if (selectedOption === 'Yes') {
                 return this.save();
             } else {
                 Q.resolve()
             }
         });
}
app.showMessage('Are you sure you want to delete this item?', 'Delete?', ['Yes', 'No'])
    .then(function (selectedOption) {
        if (selectedOption === 'Yes') {
            item.entityAspect.setDeleted();
            datacontext.saveChanges()
                .then(function () {
                    logger.logNotificationInfo('Item deleted.', '', router.activeInstruction().config.moduleId);
                    Q.resolve(this.refresh(true));
                }.bind(this));
            }
       }.bind(this));

来自durandal的app.showMessage调用返回一个promise,然后this.save返回一个promise,最后this.refresh也返回一个promise .

所以我想我需要检查hasChanges,然后在必要时调用save,并解决它 . 然后在该条件部分完成解析后,调用第二个提示,然后解析其中的所有promise .

对不起,我不认为这是非常明确的,但我认为这也是因为我并没有完全遵循这里的链条 .

任何帮助非常感谢!谢谢 .

3 回答

  • 7

    如果在promise中抛出错误,该进程将直接跳转到第一个.fail / .catch处理程序,跳过其中的任何 .thens() .

    function AbortError() {}
    
    MyClass.prototype.delete = function() {
        var p = Q();
        var self = this;
        if( this.hasChanges() ) {
            p = app.showMessage('...', '...', ['Yes', 'No'])
            .then(function(answer){
                if( answer === "Yes") {
                    return self.save(); //I assume save returns a promise
                }
                throw new AbortError();
            });
        }
        return p
        .then(function() {
            return app.showMessage('...', '...', ['Yes', 'No'])
        })
        .then(function(answer) {
            if( answer === "yes") {
                item.entityAspect.setDeleted();
                return datacontext.saveChanges();
            }
            throw new AbortError();
        })
        .then(function(){
            logger.logNotificationInfo('Item deleted.', '', router.activeInstruction().config.moduleId);
            self.refresh(true);
        })
        .fail(function(e){
            //kris please provide typed .catch feature :(
            if( !(e instanceof AbortError) ) {
                throw e;
            }
        });
    };
    
  • 2

    克里斯是对的 . 您不需要任何Q.resolve调用 .

    顺便说一句,在你的情况下,返回一个具有已解决 Value truefalse 的承诺是毫无意义的 . 我担心你会错误地认为返回 false 会阻止被锁定的 then() . 不是这样!值为 false 的已解决的承诺仍然是一个很好的承诺......如以下代码中所示,它触发警报消息框:

    Q(false) // same as Q.resolve(false)
     .then(function () { alert('resolve(false) triggered then()') })
    

    如果要将promise置于失败状态(并且您不关心错误值),则应返回 Q.reject() .


    我不知道 this 在你的代码中是什么,但是它会因为补偿 bind(this) 逻辑而迷失方向 .


    我不完全确定你要做什么 . 在未保存的更改中,您似乎不会继续删除项目 . 如果用户确定,您将保存未保存的更改 . 然后,您将要求用户确认删除 . 如果用户拒绝保存挂起的更改,您甚至不应该开始删除过程 .

    如果我理解正确,我想你想要这样的东西:

    var self = this; // WHAT IS THIS? I don't know but capture it as 'self'
    
    function saveBeforeDeleting() {
      return saveIfNeeded().then(deleteIfConfirmed);
    }
    
    function saveIfNeeded() {
      // no need to save; return resolved promise
      if (!self.hasChanges()) return Q();
    
      var dialogPromise = app.showMessage(
        'Changes must be saved before removing external accounts. '+
        'Would you like to save your changes now?', 
        'Unsaved Changes...', ['Yes', 'No']
      );
    
      // When the user replies, either save or return a rejected promise
      // (which stops the flow)
      return dialogPromise.then(function (selectedOption) {
        return (selectedOption === 'Yes') ? self.save() : Q.reject();
      });
    }
    
    function deleteIfConfirmed() {
      var dialogPromise = app.showMessage(
        'Are you sure you want to delete this item?', 
        'Delete?',
        ['Yes', 'No']
      );
    
      return dialogPromise.then(function (selectedOption) {
        return (selectedOption === 'Yes') ? deleteIt() : Q.reject();
      });
    
      function deleteIt() {
         item.entityAspect.setDeleted();
         return datacontext.saveChanges().then(logAndRefresh);
      }
    
      function logAndRefresh() {
         logger.logNotificationInfo(
           'Item deleted.',
           '', 
           router.activeInstruction().config.moduleId
         );
         return self.refresh(true));
      }
    }
    

    显然我还没有测试过这段代码 . 把它想象成灵感 .

  • 11

    一般来说,你想要创建函数来完成你的工作,总是返回一个promise,即使这是一个立即解决的函数,即“return Q.resolve(someData)” .

    所以我会尝试类似下面的内容 . 请注意下面的额外“返回”声明 .

    function complexSave() {
       return saveIfNeeded().then(confirmDelete);
    }
    
    // returns a promise
    function saveIfNeeded() {
      if (this.hasChanges()) {
        return app.showMessage('Changes must be saved before removing external accounts.  Would you like    to  save your changes now?', 'Unsaved Changes...', ['Yes', 'No']).
          then(function (selectedOption) {
             if (selectedOption === 'Yes') {
                 return this.save();
             } else {
                 return Q.resolve(false)
             }
         });
      else {
        return Q.resolve(false);
      }
    }
    
    // returns a promise
    function confirmDelete() {
      return app.showMessage('Are you sure you want to delete this item?', 'Delete?', ['Yes', 'No'])
        .then(function (selectedOption) {
           if (selectedOption === 'Yes') {
              item.entityAspect.setDeleted();
              return datacontext.saveChanges()
                .then(function () {
                    logger.logNotificationInfo('Item deleted.', '', router.activeInstruction().config.moduleId);
                    return Q.resolve(this.refresh(true));
                }.bind(this));
            } else {
              return Q.resolve(false);
            }
       }.bind(this));
    }
    

相关问题