향상된 API 및 ReScript

17336 단어 reasonrescript
JavaScript의 세계에서 많은 API의 디자인은 기능 개발자가 디자인할 수 있는 것이 아니다.비록 지난 몇 년 동안, React 등 기술의 도움으로 인해, 그것은 더욱 좋아졌지만, 대부분의 브라우저 API는 여전히 대상을 대상으로 하거나 더 낮은 등급을 대상으로 한다.
ReScript (이전에는 BuckleScript) 은 정적 유형의 음성 언어, 컴파일러, 구축 시스템으로 매우 읽을 수 있는 자바스크립트를 생성한다.따라서 타자 구멍을 참을 수 없는 사람들에게는 타자 스크립트의 절호의 대체품이다.
ReScript는 JavaScript API에 쉽게 바인딩할 수 있도록 다양한 데코더를 제공합니다.
최근에 나는 브라우저의 mediaDevices API을 사용하도록 요구받았다.가장 중요한 방법 중 하나는 getUserMedia 방법으로 MediaStream 대상을 포함하는 약속을 생성한다.API 사용자가 오디오, 비디오를 요청하는지 또는 오디오와 비디오를 동시에 요청하는지 확인하는 데 필요한 매개 변수 constraints 객체도 있습니다.예를 들어, 오디오 스트림만 요청하려면 다음 JS 코드를 사용할 수 있습니다.
navigator.mediaDevices.getUserMedia({audio: true, video: false})
비디오에만 audio: false, video: true을 설정하고 두 가지가 필요한 경우에만 audio: true, video: true을 설정합니다.
이러한 API는 일반적인 ReScript에서 다음 방법 중 하나로 설계될 수 있습니다.
  • 또는 constraints 변형:
  • type constraints = Audio | Video | Both
    
    let getUserMedia: constraints => Js.Promise.t<stream> = ...
    
    /* Calling the function */
    getUserMedia(Audio)
    getUserMedia(Video)
    getUserMedia(Both)
    
  • 또는 3가지 개별 기능
  • let getUserAudio: unit => Js.Promise.t<stream> = ...
    let getUserVideo: unit => Js.Promise.t<stream> = ...
    let getUserMedia: unit => Js.Promise.t<stream> = ...
    
    /* Calling the function */
    getUserAudio()
    getUserVideo()
    getUserMedia()
    
    이런 상황에서 나는 후자를 더욱 좋아한다.곧 알게 될 거야, 왜.

    바깥쪽을 껴안다
    기존 JS 함수에 연결하는 기본 방식은 external 키워드를 사용하고 일련의 다른 수식자/주석을 덧붙이는 것입니다. 항상 @으로 시작합니다.

    NOTE: With the most current bundle of the ReScript platform (bs-platform 8.3), it will be possible to omit the bs part in the annotations. So @bs.as will turn to just @as, etc. Check if your version is new enough for even cleaner code.



    바인딩 시도 1navigator.mediaDevices.getUserMedia 등 전역 값에 귀속시키려면 두 개의 주석이 필요합니다.귀속을 어떻게 작성하는지 보고 나중에 여러 부분으로 분해합시다.
    /* Navigator.MediaDevices module */
    type constraints = {
      audio: bool,
      video: bool,
    }
    
    @bs.val @bs.scope(("navigator", "mediaDevices"))
    external _getUserMedia: constraints => Js.Promise.t<stream> =
      "getUserMedia"
    
  • type constraints = ... :
    첫 번째 부분은 getUserMedia 함수에 대한 제약 매개 변수의 유형 정의입니다.그것은 이른바 기록으로 하나의 대상처럼 보이고 같은 모양의 JS 대상으로 컴파일되었지만 실제로는 something different이다.
  • @bs.val이 글로벌 값에 바인딩됩니다.글로벌 값은 범위 내에서 항상 존재하는 값입니다(예: navigator 또는 window).물론 이것은 목표 플랫폼(브라우저, 노드 등)에 달려 있다.
  • @bs.scope(("navigator", "mediaDevices")): 이 값을 끼워 넣을 때도 @bs.scope을 사용하여 그 범위를 정의해야 한다.여기에서, 우리는 컴파일러의 역할 영역이 다차원적이라는 문자열 그룹을 사용합니다.(())은 쌍원조이기 때문에 하나의 원조임을 알 수 있다.외원괄호는 scope 함수에서 왔고, 내원괄호는tuple에서 왔다.또는 다음 내용을 나타내는 문자열을 사용할 수도 있습니다: @bs.scope("navigator.mediaDevices").
  • external _getUserMedia: 위 주석은 external 키워드와 함께 사용됩니다.바인딩할 JavaScript 메서드와 같을 필요가 없는 바인딩의 이름을 정의할 수 있습니다.
  • : constraints => Js.Promise.t<stream>: 그리고 유형 주석.MDN에 따르면 앞에서 언급한constraints 대상을 받아들이고 미디어스트림의 약속을 되돌려줍니다. 이 약속은 내장된 ReScript 유형 Js.Promise.t으로 전환됩니다.유감스럽게도promise로 포장된 <stream> 유형은 내장된 것이 아니지만 이에 상응하여 입력할 수 있다(독자에게 연습용으로 남겨준다)😉).
  • = "getUserMedia": 마지막으로 함수의 실제 이름을 가진 문자열입니다.타자 오류를 조심해라!
  • 우리는 또 조수 기록을 정의했다.객체처럼 보이며 JS 객체로 컴파일되지만 실제로는 다릅니다.
    현재 우리는 getUserMedia까지 귀속되어 있지만 코드 라이브러리 중 어느 곳에서든 추악한 Navigator.MediaDevices._getUserMedia({audio: true, video: true}이라고 부르고 싶습니까, 아니면 우리가 더 좋은 API를 실현할 수 있을까요?
    도움말 함수를 작성해 보겠습니다.
    /* Navigator.MediaDevices module continued */
    let getUserAudio = () => _getUserMedia({audio: true, video: false})
    let getUserVideo = () => _getUserMedia({audio: false, video: true})
    let getUserMedia = () => _getUserMedia({audio: true, video: true})
    
    그런 다음 다음 다음 코드 라이브러리의 모든 위치에서 이러한 함수를 호출할 수 있습니다.
    Navigator.MediaDevices.getUserAudio()
    Navigator.MediaDevices.getUserVideo()
    Navigator.MediaDevices.getUserMedia()
    

    NOTE: Simplified example, in practice you would use Js.Promise.then_ or the like, to retrieve the stream itself.


    아, 많이 좋아진 것 같아.그런데 지금 저희가 추가 코드를 만들었어요.
    예를 들어 이 함수는
    function getUserAudio(param) {
      return navigator.mediaDevices.getUserMedia({
                  audio: true,
                  video: false
                });
    }
    

    바인딩 시도 2
    우리는 더 잘할 수 있을 뿐만 아니라, 기본 매개 변수로 함수를 채울 수 있습니까?그래, 이 예쁜 수작으로.
    실체에 복잡한 이름을 붙여야 한다면 만들 수 없는 아주 유용한 @bs.as 주석이 있습니다.예를 들어 기록 필드에서 -을 사용할 수 없습니다. 이 주석을 통해 완화할 수 있습니다.@bs.as은 단일 문자열을 매개 변수로 사용합니다.공교롭게도 JSON은 기본적으로 복잡한 문자열일 뿐이기 때문에 우리는 일부 복잡한 대상을 기본 설정에 주입할 수 있다.
    그냥 쓰세요.
    @bs.as(json`{your-config-object}`)
    
    이후 _ 호출 함수를 사용할 때 이 값을 무시합니다.
    그 밖에 우리는 최종 unit(함수의 유일한'매개 변수')을 추가했다.
    /* Navigator.MediaDevices module */
    @bs.val @bs.scope(("navigator", "mediaDevices"))
    external getUserAudio: (
      @bs.as(json`{"audio": false, "video": true}`) _,
      unit,
    ) => Js.Promise.t<stream> = "getUserMedia"
    
    하지만 내가 말한 JSON 기교에도 한계가 있다.배열, 객체, 문자열, 숫자 및 부울 값과 같은 JSON 값에만 적용됩니다.예를 들어, 함수가 작동하지 않습니다.
    다른 두 가지 가능한 기능에 대해 동일한 작업을 수행할 수 있습니다.
    /* Navigator.MediaDevices module continued */
    @bs.val @bs.scope(("navigator", "mediaDevices"))
    external getUserVideo: (
      @bs.as(json`{"audio": true, "video": false}`) _,
      unit,
    ) => Js.Promise.t<stream> = "getUserMedia"
    
    @bs.val @bs.scope(("navigator", "mediaDevices"))
    external getUserMedia: (
      @bs.as(json`{"audio": true, "video": true}`) _,
      unit,
    ) => Js.Promise.t<stream> = "getUserMedia"
    
    결국 시도 1과 동일한 API가 제공됩니다.마찬가지로 우리는 이전과 같이 함수를 호출할 수 있다.
    Navigator.MediaDevices.getUserAudio()
    Navigator.MediaDevices.getUserVideo()
    Navigator.MediaDevices.getUserMedia()
    
    그러나 이번에 부품을 구축하지 않았기 때문에 두 번째 시도의 원가는 0이었다🎉.
    경험치 법칙: let은 추가 JS 코드를 생성하고 external은 생성하지 않습니다.
    당신들의 독서에 감사드립니다. 나는 이 기교가 당신들 중 일부에게 도움이 되기를 바랍니다.간단명료한 예를 들어 이 블로그가 바탕으로 한 ReScript playground example을 보십시오.

    좋은 웹페이지 즐겨찾기