16

我还没有完全理解承诺,如果这是一个简单的误解,我深表歉意。

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

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 调用返回一个承诺,然后 this.save 返回一个承诺,最后 this.refresh 也返回一个承诺。

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

对不起,我认为这不是很清楚,但我认为这也是因为我没有完全遵循这里的链条。

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

4

3 回答 3

11

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

顺便说一句,返回具有已解决值的承诺,true或者false在您的情况下毫无意义。我担心你会误以为返回false会阻止被锁住then()的人被召唤。不是这样!值为 的false已解决承诺仍然是一个好的承诺......如以下触发警报消息框的代码所示:

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

如果你想将 Promise 置于失败状态(并且你不关心错误值),你应该 return 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));
  }
}

显然我还没有测试过这段代码。将其视为灵感。

于 2013-10-22T09:32:48.377 回答
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;
        }
    });
};
于 2013-10-22T13:23:57.037 回答
2

一般来说,您希望创建函数来完成您的工作,这些函数总是返回一个承诺,即使这是一个立即解决的承诺,即“返回 Q.resolve(someData)”。

所以我会尝试以下类似的方法。请注意下面额外的“return”语句。

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));
}
于 2013-10-21T23:39:57.187 回答