2013-10-21 2 views
15

나는이 약속을 완전히 이해하지 못했기 때문에 간단한 오해 일 경우 사과드립니다.Q.js를 사용하여 조건부 (?) 약속을 올바르게 연결하는 방법

페이지의 항목을 삭제하는 기능이 있지만 페이지 상태에 따라 특정 동작이 있습니다. 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과 breeze를 사용하고 있는데, 그들이 올바르게 돌아 오는 약속을 묶어 놓을 수는없는 것 같습니다.

내 기능은 현재 다음과 같이 보이는데, 나는 틀린 것을 알고 있지만, 문제를 해결하기 위해 고심하고 있습니다.

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를 호출하여 해결해야합니다. 그런 다음 조건부 섹션에서 해결이 완료되면 두 번째 프롬프트를 호출하고 그 안에있는 모든 약속을 해결하십시오.

죄송 합니다만 이것이 명확하지 않다고 생각합니다.하지만 사실은 여기에서 사슬을 완전히 따르지 않고있는 것 같습니다.

많은 도움을 주셨습니다. 감사.

답변

11

크리스가 맞습니다. Q.resolve 호출이 필요하지 않습니다.

Btw, 해결 된 값이 true 또는 false 인 약속을 반환하는 것은 의미가 없습니다. false을 반환하면 체인 then()이 호출되는 것을 방지 할 것이라는 잘못된 인상을 받고 있습니다. 별로! false의 값을 가진 해결 약속은 여전히 ​​좋은 약속입니다 ... 경고 메시지 상자를 트리거 다음 코드와 같이 :

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

실패한 상태에서 약속을 넣어하려는 경우

(그리고 오류 값에 대해 신경 쓰지 마십시오), 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)); 
    } 
} 

는 분명 내가이 코드를 테스트하지 않았습니다 :

만약 내가 제대로 이해하고

, 난 당신이 뭔가를하려는 생각합니다. 그것이 영감으로 생각하십시오.

+0

기본적으로이 코드를 모두 사용했기 때문에이를 답변으로 표시했습니다.하지만 모든 사람들의 대답은 본질적으로 정확합니다. – Adam

+0

이 대회에 관해서, 나는 자기 패턴이 그것이 어떻게 이루어져야 하는지를 안다. 그러나 불행하게도 나는 자기와 클로저가 올바르게 작동하지 못하는 상황을 발견했다. 그런 다음 바인드에 대해 알아 낸 후 수정했습니다. 효과가있어 막혔습니다. 별로. – Adam

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)); 
} 
+3

이 모든 Q.resolve 호출은 필요하지 않습니다. 모든 값은 promise 핸들러에서 리턴 될 수 있으며 자동으로 랩핑됩니다. –

+1

끔찍한 약속의 피라미드 – mumair

7

약속을 잘못하면 프로세스가 바로 첫 번째 .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; 
     } 
    }); 
}; 
관련 문제