2010-01-29 4 views
13

저는 this article을 읽었으며 약속의 추상화에 관한 부분은 다소 복잡하게 보입니다. 예로서 주어진 다음CommonJS에서 '약속'추상화의 이점은 무엇입니까?

requestSomeData("http://example.com/foo") // returns a promise for the response 
    .then(function(response){ // ‘then’ is used to provide a promise handler 
     return JSON.parse(response.body); // parse the body 
    }) // returns a promise for the parsed body 
    .then(function(data){ 
     return data.price; // get the price 
    }) // returns a promise for the price 
    .then(function(price){ // print out the price when it is fulfilled 
     print("The price is " + price); 
    }); 

적은 코드로 동일한 결과를 제공 할 수있는 다음과 같은 것을 나에게 보인다

requestSomeData("http://example.com/foo") 
    .requestHandler(function(response){ 
     // parse the body 
     var data = JSON.parse(response.body); 

     // get the price 
     var price = data.price; 

     // print out the price 
     print("The price is " + price); 
    }); 
+2

당신 맞습니다. 동기 작업에 약속을 사용하는 데는 아무런 포인트가 없습니다. 따라서 결과는 동일해야합니다. 그러나 그것은 예이며 약속의 사용법을 설명합니다. 귀하의 예제 다음에 실행되는 코드에는 실제로 차이가 있습니다. 예제 코드가 무엇을하는지 알지 못해서 (promise 접근법을 사용하여) 할 수있는 것보다 예제 후에 뭔가를 실행할 필요가 있다면 –

답변

17

는 모두 궁극적으로 달성 할 것은 사실이지만 똑같은 차이점은 두 번째 예제가 비동기 적이 지 않다는 것입니다. 예를 들어, JSON.parse(...)이 매우 비싼 작업으로 밝혀지면 어떻게 될지 생각해보십시오. 모든 것이 끝날 때까지 기다려야 할 것입니다. 그것은 항상 당신이 원하는 것이 아닐 수도 있습니다.

그게 당신에게 약속하는 것입니다.보다 편리한 시간까지 올바른 대답의 계산을 연기 할 수있는 강력한 능력입니다. 이름에서 알 수 있듯이이 구조는 어느 시점에서 결과를 제공하겠다고 약속하고 있습니다. 꼭 지금 당장 필요하지는 않습니다. 선물과 약속에 대한 자세한 내용은 큰 규모의 here에서 확인할 수 있습니다.

+2

여기에 편리한 시간은 뭔가요? 작업이 매우 비싸고 JSON.parse가 자바 스크립트 코드 조각이라면 어쨌든 중단됩니다. 차이점은 실제로 실행중인 기능을 완료 할 수 있다는 약속과 함께있는 것입니다. –

+3

파싱은 동 기적으로 계산되는지 비동기 적으로 계산되는지에 관계없이 동일한 시간이 소요됩니다. 그러나 작은 조각의 작업을 완료 한 후 예상대로 이벤트 루프에 도달하는 방식으로 파서를 구현하는 데 시간이 걸리면 다른 비동기 코드가 각 청크간에 비동기 적으로 실행될 수 있습니다. 따라서 애플리케이션이 응답 속도가 빨라집니다. –

+0

JSON.parse가 원시 메소드가되어 다른 스레드에서 실행될 수 있습니다. – Jan

3

이의 순수 자바 스크립트 예제에 약속의 예를 비교해 보자 : 노 베르트있는 Hartl는 지적

// First we need a convenience function for W3C's fiddly XMLHttpRequest. 
// It works a little differently from the promise framework. Instead of 
// returning a promise to which we can attach a handler later with .then(), 
// the function accepts the handler function as an argument named 'callback'. 

function requestSomeDataAndCall(url, callback) { 
    var req = new XMLHttpRequest(); 
    req.onreadystatechange = resHandler; 
    req.open("GET", url, false); 
    req.send(); 
    function resHandler() { 
     if (this.readyState==4 && this.status==200) { 
      callback(this); 
     } else { 
      // todo: Handle error. 
     } 
    } 
} 

requestSomeDataAndCall("http://example.com/foo", function(res){ 
    setTimeout(function(){ 
     var data = JSON.parse(res.responseText); 
     setTimeout(function(){ 
      var price = data.price; 
      setTimeout(function(){ 
       print("The price is "+price); 
      },10); 
     },10); 
    },10); 
}); 

, JSON.parse()가 큰 문자열 브라우저를 중단됩니다. 그래서 setTimeout()을 사용하여 실행을 지연 시켰습니다 (10 밀리 초의 일시 중지 이후). 이것은 Kris Kowal의 솔루션의 한 예입니다. 콜백이 실행되기 전에 현재 자바 스크립트 스레드가 완료되어 브라우저에서 DOM 변경 사항을 표시하고 사용자를 위해 페이지를 스크롤 할 수 있습니다.

commonjs 약속 프레임 워크에서도 setTimeout과 같은 것을 사용하기를 바랍니다. 그렇지 않으면 기사 예제의 나중 약속이 실제로 두려움에 따라 동 기적으로 실행됩니다.

내 위의 대체 방법은 꽤 추한 것처럼 보입니다. 이후 프로세스는 들여 쓰기가 더 필요합니다. 내가 자바 스크립트에서 콜백의 전통 앞으로 전달을 보여 기대하고 있었는데

function makeResolver(chain) { 
    function climbChain(input) { 
     var fn = chain.shift();  // This particular implementation 
     setTimeout(function(){  // alters the chain array. 
      var output = fn(input); 
      if (chain.length>0) { 
       climbChain(output); 
      } 
     },10); 
    } 
    return climbChain; 
} 

var processChain = [ 
    function(response){ 
     return JSON.parse(response.body); 
    }, 
    function(data){ 
     return data.price; // get the price 
    }, 
    function(price){ 
     print("The price is " + price); 
    } 
]; 

var climber = makeResolver(promiseChain); 
requestSomeDataAndCall("http://example.com/foo", climber); 

하는 약속을 거의 동일합니다 : 우리가 모두 하나 개의 수준에서 우리의 프로세스 체인을 제공 할 수 있도록 내가 코드를 재구성. 그러나 두 번의 시도 후에 나는 본보기의 코드의 깔끔함과 관련하여 약속이 훨씬 더 우아한 해결책이라는 것을 보여준 것처럼 보입니다!

0

두 번째 버전보다 첫 번째 버전의 장점은 세분화 체인에서 다른 작업을 구분한다는 것입니다 (기능을 현재 위치에 쓸 필요는 없습니다). 두 번째 버전은 낮은 수준의 구문 분석과 응용 프로그램 논리를 혼합합니다. 특히 SOLID 원칙을 지침으로 사용하면 두 번째 버전은 OCPSRP을 모두 위반합니다.

1

example.com/foo가 잘못된 json을 반환하여 서버를 크래시 할 수 있기 때문에 두 번째 코드 단편은 서비스 거부 공격에 취약합니다. 빈 응답이라도 유효하지 않은 JSON입니다 (유효한 JS 임에도 불구하고). 예를 들어 mysql_*과 같이 눈부신 SQL 주입 구멍이 있습니다.

그리고 약속 코드를 많이 향상시킬 수 있습니다.이들은 같다 :

requestSomeData("http://example.com/foo") // returns a promise for the response 
    .then(function(response){ // ‘then’ is used to provide a promise handler 
     // parse the body 
     var data = JSON.parse(response.body); 

     // get the price 
     var price = data.price; 

     // print out the price 
     print("The price is " + price); 
    }); 

그리고 :

requestSomeData("http://example.com/foo") // returns a promise for the response 
    .then(function(response){ // ‘then’ is used to provide a promise handler 
     // parse the body 
     var data = JSON.parse(response.body); 

     // get the price 
     var price = data.price; 

     // print out the price 
     print("The price is " + price); 
    }).catch(SyntaxError, function(e) { 
     console.error(e); 
    }); 

과 :

requestSomeData("http://example.com/foo") 
    .requestHandler(function(response){ 
     try { 
      var data = JSON.parse(response.body); 
     } 
     catch(e) { 
      return; 
     } 

     // get the price 
     var price = data.price; 

     // print out the price 
     print("The price is " + price); 
    }); 

우리가 오류를 처리하고 싶다면, 다음이 동등한 것

requestSomeData("http://example.com/foo") 
    .requestHandler(function(response){ 
     try { 
      var data = JSON.parse(response.body); 
     } 
     catch(e) { 
      //If the above had a typo like `respons.body` 
      //then without this check the ReferenceError would be swallowed 
      //so this check is kept to have as close equality as possible with 
      //the promise code 
      if(e instanceof SyntaxError) { 
       console.error(e); 
       return; 
      } 
      else { 
       throw e; 
      } 
     } 

     // get the price 
     var price = data.price; 

     // print out the price 
     print("The price is " + price); 
    }); 
관련 문제