2013-10-21 6 views
15

私は約束を完全に理解していないので、これが単純な誤解である場合にはお詫び申し上げます。Q.jsで条件付き(?)約束を正しく連結する方法

私はページ上のアイテムを削除する機能を持っていますが、私はページの状態によって特定の動作があります。擬似コードそれはこのようなものです:

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

app.showMessageコールは約束を返し、その後、this.saveは約束を返し、最後にthis.refreshも約束を返します。

だから、hasChangesをチェックし、必要に応じてsaveを呼び出して解決する必要があると思います。 その後、その条件付きセクションの解決が完了したら、2番目のプロンプトを呼び出して、その中のすべての約束を解決します。

申し訳ありませんがこれは非常に明確だとは思わないが、それは私がここのチェーンを完全にフォローしていないという事実から来ているとも思う。

ご迷惑をおかけして申し訳ありません。ありがとう。

答えて

11

クリスが正しい。 Q.resolve呼び出しは必要ありません。

解決済みの値が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

一般に、すぐに解決されるものであっても、常に「約束を返す」(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呼び出しはすべて不要です。すべての値は約束ハンドラから返され、自動的に折り返されます。 –

+1

ひどい約束のピラミッドdoom – 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; 
     } 
    }); 
};