2016-08-04 5 views
2

비동기/대기 코드 (Typescript + es6 target)을 어떻게 연결하여 Promise.then()으로 변환합니까? 예를 들어일반 문자로 약속 연결하기

:

function mockDelay<T>(getValue:()=>T): Promise<T> { 
    return new Promise<T>(resolve=>setTimeout(()=>resolve(getValue()), 10)); 
} 
// Assume blackbox implementation 
class Service { 
    constructor(private i=1, private callCount=0){} 
    opA() : Promise<number> { 
     this.callCount++; 
     return mockDelay(()=>this.i+=1); 
    } 
    opB(value:number) : Promise<number> { 
     this.callCount++;  
     return mockDelay(()=>this.i+=value); 
    } 

    opC(): Promise<number> { 
     return mockDelay(()=>this.i+=2); 
    } 

    isA(): Promise<boolean> { return mockDelay(()=>this.callCount%2===0); } 
    isC(): Promise<boolean> { return mockDelay(() =>true); } 
} 

// Convert this async/await code to using chained Promises 
async function asyncVersion(): Promise<string[]>{ 
    let expected:string[] = []; 
    let lib = new Service(); 
    let sum = 20; 
    let lastValue = 0; 
    while (sum > 0) { 
     expected.push(`${sum} left`); 
     if (await lib.isA()) 
     { 
      expected.push("Do A()"); 
      lastValue = await lib.opA(); 
      sum -= lastValue; 
     } 
     else 
     { 
      expected.push("Do B()"); 
      lastValue = await lib.opB(lastValue); 
      sum -= lastValue*3; 
      if (await lib.isC()) { 
       expected.push("Do C()"); 
       sum += await lib.opC(); 
      } 
     } 
    } 
    expected.push("All completed!"); 
    return expected; 
}; 

function chainPromiseVersion(): Promise<string[]>{ 
    // How to convert the asyncVersion() to using chained promises? 
    return Promise.resolve([]); 
} 

// Compare results 
// Currently running asyncVersion() twice to ensure call results are consistent/no side effects 
// Replace asyncVersion() with chainPromiseVersion() 
Promise.all([asyncVersion(), asyncVersion() /*chainPromiseVersion()*/]) 
    .then(result =>{ 
     let expected = result[0]; 
     let actual = result[1]; 
     if (expected.length !== actual.length) 
      throw new Error(`Length: expected ${expected.length} but was ${actual.length}`); 
     for(let i=0; i<expected.length; i++) { 
      if (expected[i] !== actual[i]){ 
       throw new Error(`Expected ${expected[i]} but was ${actual[i]}`); 
      } 
     } 
    }) 
    .then(()=>console.log("Test completed")) 
    .catch(e => console.log("Error: " + e)); 

나는 바벨 (Github example)를 사용하여 ES5하는 ES6 코드를 transpile 수 있습니다 알고 있습니다.

이 질문은 비동기/대기 코드를 사용하여 코드를 수동으로 다시 쓰는 것에 관한 것입니다.

다음과 같은 간단한 예를 변환 할 수 있습니다.

// Async/Await 
(async function(){ 
    for (let i=0; i<5; i++){ 
     let result = await mockDelay(()=>"Done " + i); 
     console.log(result); 
    } 
    console.log("All done"); 
})(); 

// Chained Promises 
(function(){ 
    let chain = Promise.resolve(null); 
    for (let i=0; i<5; i++){ 
     chain = chain 
      .then(()=>mockDelay(()=>"Done " + i)) 
      .then(result => console.log(result)); 
    } 
    chain.then(()=>console.log("All done")); 
})(); 

그러나

어떻게 위의 경우의 예를 변환하는 아무 생각이 :
  • 실행해야합니다

    • 루프 조건 약속의 결과에 영향을 한 후 - 더 - 다른 (어떤 Promise.all())
  • +0

    왜 당신이 원하는 것까지? – Bergi

    +0

    방법을 알아보십시오. 나의 최종 목표가 단순히 async/es5를 목표로하는 코드를 기다리는 것이라면, 나는 Babel과 함께 이미 번쩍 거리고있을 것입니다. – jayars

    답변

    1

    await이되면호출이됩니다. 범위 지정 및 제어 흐름을 위해 중첩 된 호출이 자주 발생하며 순환이 반복됩니다. 귀하의 경우 :

    (function loop(lib, sum, lastValue){ 
        if (sum > 0) { 
         console.log(`${sum} left`); 
         return lib.isA().then(res => { 
          if (res) { 
           console.log("Do A()"); 
           return lib.opA().then(lastValue => { 
            sum -= lastValue; 
            return loop(lib, sum, lastValue); 
           }); 
          } else { 
           console.log("Do B()"); 
           return lib.opB(lastValue).then(lastValue => { 
            sum -= lastValue*3; 
            return lib.isC().then(res => { 
             if (res) { 
              console.log("Do C()"); 
              return lib.opC().then(res => { 
               sum += res; 
               return loop(lib, sum, lastValue); 
              }); 
             } 
             return loop(lib, sum, lastValue); 
            }); 
           }); 
          } 
         }); 
        } else { 
         console.log("All completed!"); 
         return Promise.resolve() 
        } 
    })(new Service(), 20, 0); 
    

    는 다행히 당신은 그것을 더욱 복잡하게 만들었 것처럼, 루프 내부 break/ continue/ return의 어떤 형태 없었다. 일반적으로 모든 문장을 연속 통과 스타일로 변환 한 다음 필요에 따라 연기 할 수 있습니다.

    +0

    예를 들어 주셔서 감사합니다. '반복은 재귀가된다 ', 흥미로운 제어 구조 방법. 천천히 내 머리를 감싸기 시작했다.불행히도 호출 순서/결과는 원래 코드와 다릅니다. 코드를 수정하고 비교 방법을 추가하여 호출 순서/결과를 테스트했습니다. – jayars

    +0

    @jsjslim : 그렇습니까? 현재 코드를 실행할 수 없습니다. 결과를 어딘가에 게시 할 수 있습니까? – Bergi

    +0

    비교 : http://imgur.com/XguK6Lx. 첫 루프가 괜찮은 것 같아요, 두 번째 루프는 괜찮습니다 (isB()> doB()> doC()),하지만 세 번째 루프에 의해 합계는 off가됩니다 – jayars

    2

    Bergi의 대답 덕분에 단계별 변환을 async/await에서 으로 연결하는 방법을 알아 냈습니다.

    내가 도우미 함수 promiseWhile을 만들었습니다

    자신을 도와 :

    // Potential issue: recursion could lead to stackoverflow 
    function promiseWhile(condition:()=>boolean, loopBody:()=>Promise<any>): Promise<any> { 
        if (condition()) { 
         return loopBody().then(()=>promiseWhile(condition, loopBody)); 
        } else { 
         // Loop terminated 
         return null; 
        } 
    } 
    

    을 내가 사용했습니다 단계 :

    await op()이 명중 할 때마다
    • return op().then(()=>{...})
      • 로 변환 {...}await 뒤에 오는 코드입니다 (대기중인 과제 포함)
    • 이 어떤 깊은 중첩 결과,하지만 난 다음 단계를 수행하면, 나는
    • 완료되면 검증, 나는 다음에 갈 수있는 실수하고 깨끗한 일까지
    을 할 자신이 덜 찾기

    Conversion

    // Converted 
    function chainPromiseVersion(): Promise<string[]>{ 
        let expected:string[] = []; 
        let lib = new Service(); 
        let sum = 20; 
        let lastValue = 0; 
        return promiseWhile(
         // Loop condition 
         ()=>sum>0, 
    
         // Loop body 
         ()=> { 
          expected.push(`${sum} left`); 
    
          return Promise.resolve(null) 
          .then(()=>lib.isA()) 
          .then(isA => { 
           if (isA) { 
            expected.push("Do A()"); 
            return lib.opA() 
             .then(v =>{ 
              lastValue = v; 
              sum -= lastValue; 
             }); 
           } 
           else { 
            expected.push("Do B()"); 
            return lib.opB(lastValue) 
              .then(v=>{ 
               lastValue = v; 
               sum -= lastValue*3; 
               return lib.isC().then(isC => { 
                if (isC) { 
                 expected.push("Do C()"); 
                 return lib.opC().then(v => { 
                  sum += v; 
                 }); 
                } 
               }); 
              }); 
           } 
          }) // if (lib.isA()) 
         }) // End loop body 
         .then(()=>expected.push("All completed!")) 
         .then(()=>expected); 
    } 
    
    관련 문제