2017-06-20 112 views
1

我知道有類似的問題,但我沒有看到這個鏈接模式的任何地址。如何破解承諾鏈?

我有以下幾點:

var runTests = function (chain, resolutionTest) { 
     return chain.then(function (result) { 
      if (result) 
       return result; // Early return if the previous tests were successful. This is where I want to prevent other attempts. 
      const attempt = tryOpenStream(resolutionTest).then(streamToDom); 
      return attempt; 
     }); 
    } 

    // from someplace else 
    numTests = resolutionTests.length; 
    return resolutionTests.reduce(runTests, Promise.resolve()); // start reduce with an empty promise 

,我現在遇到的是,我打電話tryOpenStream多少次我拍攝的result,但問題。

選項我考慮:

  • 提出一些全局標誌,只是阻止進一步執行從鏈中。 Yuck,因爲鏈條還在繼續,它只是被清空。
  • throw new Error(result)而不是return result。這將打破連鎖(我認爲...),但它被誤用,並且很容易被其他開發者誤解。

我怎樣才能打破這條鏈return result;

更新1

我想以下幾點:

var makeTest = function (runMoreTests, resolutionTest) { 
     return function runTest() { 
      return tryOpenStream(resolutionTest).then(streamToDom).then(function (result) { 
       if (result) 
        return result; 
       else 
        return runMoreTests(); 
      }); 
     }; 
    } 

    return resolutionTestBuilder.buildTests().then(function (resolutionTests) { 
     numTests = resolutionTests.length; 
     return resolutionTests.reduceRight(makeTest, function() { Promise.reject("No resolutions succeeded.") })(); 
    }); 

但是到runTest沒有呼叫被調用。對我來說,這是一種新的語法,所以我會研究一些並更新任何發現。

更新2

我錯過了()調用reduceRight。雖然現在我看到reject即使成功也會被打電話,但是當我經過時,拒絕不會被調用。就好像到了我得到結果的時候,鏈中的所有鏈接都被調用了。

+1

你是否也看到了(這些)(https://開頭stackoverflow.com/q/28803287/1048572)[很少](https://stackoverflow.com/q/21576862/1048572)[問題](https://stackoverflow.com/q/29499582/1048572)? – Bergi

+1

重新更新2:不確定爲什麼你會拒絕承諾。你確定'streamToDom'調用之一確實返回一個真實結果,並且'runMoreTests'不總是被調用嗎?你可以做一些調試,或者將'console.log(result)'的輸出發佈到該回調中? – Bergi

+0

@Bergi我看到'return runMoreTests()'多次被調用,然後是'return result',然後'return runMoreTests()'多次被調用,直到拒絕被調用。 – SB2055

回答

1

可以使用標誌和異常,但正如您注意到的,它們不是正確的工具。

相反,使用遞歸,就像@IsiahMeadows的回答,或右折:

var makeTest = function (runMoreTests, resolutionTest) { 
    return function runTest(result) { 
     if (result) 
      return result; 
     return tryOpenStream(resolutionTest).then(streamToDom).then(runMoreTests); 
    }; 
} 

return Promise.resolve(resolutionTests.reduceRight(makeTest, x => x)(undefined)); 

或更好寫成

var makeTest = function (runMoreTests, resolutionTest) { 
    return function runTest() { 
     return tryOpenStream(resolutionTest).then(streamToDom).then(result => { 
      if (result) 
       return result; 
      else 
       return runMoreTests(); 
     }); 
    }; 
} 

return resolutionTests.reduceRight(makeTest,() => Promise.reject("nothing succeeded"))(); 
+0

剛剛更新了我的問題,我嘗試了你的建議 - 謝謝你的幫助 – SB2055

+1

我不得不承認,正確的摺疊比較深奧且很難理解,你可能想用更簡單的(可能更高性能的)遞歸方法。 – Bergi

+0

是的,我正在玩它,雖然我不完全理解它,遞歸會讓我更害怕。我原來的實現是建立在遞歸上,調試是一場噩夢。我已經用我看到的結果再次更新了我的問題 - 雖然我看到了一些有趣的結果(排除總是被調用),但它仍在工作 – SB2055

1

嘗試使用這樣的:

function runTests(resolutionTest) { 
    return tryOpenStream(resolutionTest).then(streamToDom) 
} 

// from someplace else 
function loop(tests, i) { 
    if (i === tests.length) return undefined 
    return runTests(tests[i]).then(function (result) { 
     if (result) return result 
     return loop(tests, i + 1) 
    }) 
} 
return loop(resolutionTests, 0) 

雖然我不知道你爲什麼不能使用異常來表示你的tryOpenStream失敗。這實際上會簡化你的代碼。