2017-06-20 98 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失败。这实际上会简化你的代码。