3

Javascript에 비 - 선점 형 멀티 스레딩의 매우 특정한 형태를 추가 할 방법을 찾고 있습니다. Mozilla의 Javascript 1.7은 yield을 사용하여 기본 coroutines를 지원하지만 브라우저 별 솔루션을 사용하지 않는 것이 좋습니다. 주석이 달린 Javascript 코드를 일반 Javascript로 변환하는 것을 기반으로 여러 연속 또는 coroutine 구현이 있음을 확인했습니다. 몇 가지 예는 StratifiedJS, Narrative Javascriptjwacs입니다.연속성이있는 Javascript 코드를 생성하는 트릭은 무엇입니까?

시뮬레이트 된 자바 비동기 호출을위한 완벽한 기능의 프레임 워크가 필요하지 않습니다. 구현하고자하는 특정 용도로만 필요합니다. 따라서 위의 라이브러리는 나를위한 과잉 공격입니다.

누군가 내가 그러한 전처리 기가 사용하는 기본적인 "트릭"(또는 트릭)을 가르쳐 줄 수 있습니까? Javascript에서 몇 가지 특수 코드를 생성하는 대신에 계속 사용할 수있는 특수 언어 해킹이 있습니까? 모든 관련 참조를 환영합니다.

답변

10

그것은 연속 통과 스타일입니다.

자바 스크립트는 정말 미친 트릭 계속 전달 스타일처럼, 가능, 리스프하지만 C.

자바 스크립트의 핵심 기능 언어이기 때문에의 옷을 구문으로 착용한다. 그러나 이러한 트릭은 두통을 유발합니다.

요약하면, 연속은 무엇을 다음에 할 것인가의 개념입니다. 당신이 부를 수있는 것과 똑같은 기능을 제공합니다. 또한 때로는 연속을 호출 프레임의 저장된 스택으로 봅니다. 함수 호출 스택을 실행 상태로 저장하고 나중에이 상태로 돌아가거나 "호출"할 수 있습니다.

누군가가 코드를 연속 통과 스타일로 변환하면 연속성을 얻을 수 있음을 입증했습니다. 와우! 그것은 정말 인상적입니다 :

당신은 단지 연속체의 힘을 가지고 있습니다.

이제 Javascript의 문제점은 C 구문입니다. C 구문으로 소스 코드 변환을 수행하는 것은 어렵습니다. Lisp 문법으로는 더 쉬울 지 모르지만 여전히 지루하고 오류가 발생하기 쉽습니다.

우리는 정말 독창적 인 사람들이 우리를 위해 열심히 일한 것을 행운입니다. 이 어려운 작업은 Javascript 파서의 사용을 수반합니다.이 변환이 실제로 의미하는 바는 무엇인가? 요약하면 실제로 수행 된 작업이 먼저 오도록 작업 순서를 재정렬하는 것을 의미합니다.

f(g(a + x)) 

첨가 a + x 다음 함수를 호출 한 후 g()f() 먼저 수행된다. 세 가지 하위 표현식이 있습니다. CPS 변환에서 하위 표현식의 결과는 연속으로 전달됩니다. 이것은 일시적인 연속으로서 많은 내부 도우미 기능의 생성을 수반합니다. 아래에서 보게 될 것처럼 복잡하고 지루할 수 있습니다.http://en.wikipedia.org/wiki/Continuation-passing_style에서

(define (pyth x y) 
    (sqrt (+ (* x x) (* y y)))) 

(define (pyth& x y k) 
    (*& x x (lambda (x2) 
     (*& y y (lambda (y2) 
       (+& x2 y2 (lambda (x2py2) 
          (sqrt& x2py2 k)))))))) 

이 Javacript

function pyth(x, y) { 
    return Math.sqrt(x * x + y * y); 
} 

하지만 * + 및 Math.sqrt()에 해당하는 변환되는 예시적인 기능은 기능하지 여기서 CPS는 의미가 있습니다.

그러나 *, + 및 Math.sqrt()가 웹 서비스임을 가정합니다. Javascript 웹 서비스 호출이 비동기식이기 때문에 이것은 중요합니다. 비동기식 호출로 작업 한 모든 사람은 결과를 결합하는 데 얼마나 복잡한 지 압니다. 전처리 라이브러리 또는 생성기를 사용하면 비동기 결과에 쉽게 대처할 수 있습니다. 다음과 같이 할 수

function pyth(x, y) { 
    return sqrt(add(mul(x, x), mul(y, y))); 
} 

는 다음 CPS 변환 :

그럼 다른 방법으로 예를 작성할 수 우리는 코드를 생성하는 것은 내부 아웃 찢어 적극적으로 만들어 볼

function pyth_cps(x, y, k) { 
    mul_cps(x, x, function(x2) { 
    mul_cps(y, y, function(y2) { 
     add_cps(x2, y2, function(x2py2) { 
     sqrt_cps(x2py2, k); 
     }) 
    }) 
    }); 
} 

을 읽을 수 없습니다. 각 기능이 변형됩니다. 그들 모두는 마법 매개 변수 k를 얻습니다. 그게 계속됩니다. 자바 스크립트에서는 작업 결과를 가져 오는 함수입니다. 호출 스택 k의 어딘가 깊은 곳까지 호출됩니다. 이 예에서는 여기에 표시되지 않은 sqrt()의 CPS 변환에 사용됩니다.

또한 CPS로 변환 된 함수는 절대로 반환되지 않습니다. 그들은 단지 계산의 결과로 계속을 부릅니다. 이로 인해 스택이 고갈 될 수 있습니다. 모든 Javascript CPS 변환기가이를 처리해야합니다. Scheme에서는 모든 호출이 꼬리 호출이기 때문에 이것이 필요하지 않습니다. 꼬리 호출에는 추가 호출 프레임이 필요하지 않습니다. 자바 스크립트에서는 트램펄린이나 비슷한 기술이 필요합니다. 연속을 직접 호출하는 대신 도우미를 호출하고 결과와 연속을 전달합니다. 도우미는 무한 루프로 실행되어 스택 호출을 항상 호출하고 리턴하며 스택 고갈을 피합니다.

그럼 왜이 CPS가 우리에게 연속성의 힘을 주는가? 그것은 연속이 바로 다음에해야 할 일이기 때문입니다. 우리가 항상 추가 매개 변수 k로서 수행 될이 무언가의 개념을 항상 수행하고 현재 표현식의 결과를 항상 전달한다면, 우리는이 개념을 코드에서 깨달았습니다. 그러나, 우리가 보았 듯이,이«항상 가지고 다니는»은 깨닫지 못합니다.

우리는 소스 코드 전 처리기가 힘든 일을하더라도 그렇게 대가를 지불해야합니다. 왜 우리는 연속체를 사용해야합니까? 제어 흐름을 추상화하는 것이 가능합니다. 웹 애플리케이션 프레임 워크 인 Seaside는 지속성을 사용하여 브라우저의 상태 비 저장 요청 흐름을 추상화합니다. 사용자 상호 작용은 간접적으로 모델링 될 수 있습니다. 하나는 요청에서 더 이상 생각하지 않지만 상호 작용 흐름에서는 생각할 수 있습니다. 이것은 단지 연속체의 힘의 많은 예들 중 하나 일뿐입니다. 이 힘은 또한 많은 사람들에게 이상하고 다소 무서운 것처럼 보입니다.

+0

저는 CPS를 잘 알고 있지만, 일반형 명령형 코드를 la-javascript로 변환하는 것은 그렇게 간단하지 않습니다. 순차 코드에서 CPS로 자동 변환하는 방법은 무엇입니까? –

+0

먼저 소스 코드를 구문 분석 한 다음 표현식을 재 배열하여 첫 번째 하위 표현식이 평가되고 표현식의 결과가 연속으로 전달되도록합니다. I. e. 여기에 설명 된 것과 동일하게하십시오 : http://en.wikipedia.org/wiki/Continuation-passing_style, 그러나 Javascript. – nalply

관련 문제