setTimeout은 콜백 함수입니다.만약 우리가 이 점을 바꾼다면, 무슨 일이 일어날까요?


오늘날 노드식 리셋 함수를 승낙식 함수로 바꾸는 것은 흔히 볼 수 있는 방법이다.그렇다면 왜 우리는 setTimeout을 위해 이 일을 하지 않았습니까?
노드식 리셋에 비해 승낙식 함수를 선호하는 주요 원인은 Callback Hell을 피하기 위해서다.

아무도 그걸 보고 싶지 않아요.setTimeout(그리고 그의 형제 setInterval 또는 setImmediate)을 본 후에 나는 그것이 리셋 스타일의 함수라는 것을 똑똑히 볼 수 있다.
setTimeout(callback, 1000);
//         --------
//                 \
//                   See that? Right there. A callback!
그러나 setTimeout을 리셋에서 약속으로 바꾸는 사람은 드물다.setTimeout은 어떻게 레이더 아래에서 비행합니까?setTimeout의 차이로 통행증을 얻을 수 있습니까?
아니요.

노드 스타일 콜백 함수

setTimeout은 분명히 리셋 스타일의 함수이지만 노드 스타일의 리셋 함수가 아니기 때문에 무시될 수 있습니다.
우선 노드 스타일의 리셋을 살펴보고 차이를 잘 이해하자.fs.readFile은 노드식 리셋 함수의 좋은 예이다.
fs.readFile(path[, options], callback)
//                           --------
//                          /
//    callback must be last
콜백 자체는 다음과 같이 해야 합니다.
const callback = (err, data) => { /* ... */ }
//                ---  ----
//               /          \
//    error first             data last
만약에 setTimeout이 전통적인 노드 스타일 리셋 함수라면 노드의 util.promisify을 쉽게 사용하여 전환할 수 있다.다음 예는 util.promisify을 사용하여 fs.readFile을 승낙식 함수로 바꾸는 것이 얼마나 쉬운지 설명한다.
import fs from 'fs'
import { promisify } from 'util'

const readFile = promisify(fs.readFile)
불행히도 util.promisify은 일을 할 수 없을 것이다.우선, 리셋은 마지막 인자가 아니기 때문이다.그 다음으로 리셋은 (err, data) 인터페이스를 따르지 않기 때문이다.

알림 설정 시간 초과


다행히도 수동 전환도 간단하다.나는 새 함수 sleep을 호출할 것이다.
const sleep = milliseconds => value => new Promise (resolve =>
  setTimeout(() => resolve(value), milliseconds)
)
이 코드에 관해서 나는 몇 가지 관건적인 일을 지적하고 싶다.
  • sleep은 카레입니다.이따가 이유를 알게 될 거야.
  • sleep에서 value을 취한 다음에 value을 해석한다.다시 한 번 말하지만, 너는 이따가 원인을 알게 될 것이다.
  • 수면


    이제 코드에 일시 정지를 추가하는 것은 약속을 사용하는 것처럼 간단합니다.
    const log => msg => console.log(msg)
    
    sleep(1000)('Hello World').then(log)
    
    이것은 매우 좋지만, 내가 이 글을 쓴 원인은 아니다.sleep에 대해 진정으로 나를 흥분시키는 것은 그것을 약속 체인의 중간에 미끄러뜨릴 수 있다는 것이다.
    이 예에서는 API 호출 사이에 1초 지연을 추가하는 것이 간단합니다.
    import axios from 'axios'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    //                                  -
    //                                 /
    //     comma operator. google it.
    
    fetchJson('https://swapi.co/api/people/1')
      .then(log)
      .then(sleep(1000))
      .then(() => fetchJson('https://swapi.co/api/people/2'))
      .then(log)
      .then(sleep(1000))
      .then(() => fetchJson('https://swapi.co/api/people/3'))
      .then(log)
    
    sleep은 하나의 값을 입력으로 받아들이고 같은 값을 되돌려주기 때문에 이 값을 다음 약속에 전달합니다.sleep은 기본적으로 승낙체인 중간부품이 되었다.
    비동기식/대기 모드로 작성된 것을 살펴보겠습니다.
    import axios from 'axios'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    
    const main = async () => {
      const people1 = await fetchJson('https://swapi.co/api/people/1')
      log(people1)
      await sleep(1000)
      const people2 = await fetchJson('https://swapi.co/api/people/2')
      log(people2)
      await sleep(1000)
      const people3 = await fetchJson('https://swapi.co/api/people/3')
      log(people3)
    }
    
    main()
    
    솔직히 말하면, 나는 sleep이 해결한 문제를 좋아하지만, 나는 내가 방금 보여 준 코드의 문법을 그다지 좋아하지 않는다.이 두 가지 예에서 나는 사실 async/await의 문법이 더 나쁘다고 생각한다.await은 도처에 널려 있어 실수하기 쉽다.

    비동기 함수 합성


    함수 조합 기능이 강해서 많은 문장을 읽어야만 완전히 이해할 수 있을 것이다.그저 그렇다는 것이 아니라 왜다.만약 네가 시작하고 싶다면, 나는 여기서부터 시작할 것을 건의한다. Functional JavaScript: Function Composition For Every Day Use .
    나는 본문에서 함수 구성을 해석하지 않으려고 한다.나는 내가 너희들에게 보여줄 문법이 매우 간단하다고 믿는다. 너희들은 함수의 구성을 이해할 필요가 전혀 없다.
    import axios from 'axios'
    import pipe from 'mojiscript/core/pipe'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    
    const main = pipe ([
      () => fetchJson('https://swapi.co/api/people/1'),
      log,
      sleep(1000),
      () => fetchJson('https://swapi.co/api/people/2'),
      log,
      sleep(1000),
      () => fetchJson('https://swapi.co/api/people/3'),
      log
    ])
    
    main()
    
    빌어먹을!이것은 보기 좋은 코드들이다!
    그러나 우리는 이미 함수 조합을 토론하고 있기 때문에 fetchJson, log, sleep을 자신의 pipe에서 추출하여 코드를 더욱 건조하게 하기 쉽다.
    import axios from 'axios'
    import pipe from 'mojiscript/core/pipe'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = url => axios.get(url).then(response => response.data)
    const log = msg => (console.log(msg), msg)
    
    const fetchLogWait = pipe ([
      id => fetchJson (`https://swapi.co/api/people/${id}`),
      log,
      sleep(1000)
    ])
    
    const main = pipe ([
      () => fetchLogWait (1),
      () => fetchLogWait (2),
      () => fetchLogWait (3)
    ])
    
    main()
    

    비동기식 매핑


    또한 MojiScript는 비동기식 매핑의 고유한 기능을 제공합니다.(머지않아 이 방면에 관한 글 한 편이 나올 것으로 예상된다.)
    비동기 매핑은 내가 MojiScriptpipe이 아니라 RamdapipeP을 사용하여 이 예시들을 작성하기로 결정한 이유이다.지금까지 람다의 pipeP의 예도 잘 사용할 수 있다.이 점에서 예는 Mojiscript가 독점하고 있습니다.
    코드 좀 봅시다!비동기 map ajax 호출은 얼마나 쉽습니까?
    const main = pipe ([
      ({ start, end }) => range (start) (end + 1),
      map (fetchLogWait),
    ])
    
    main ({ start: 1, end: 3 })
    
    아주 간단해!

    실행 가능한 코드 블록:
    import axios from 'axios'
    import log from 'mojiscript/console/log'
    import pipe from 'mojiscript/core/pipe'
    import map from 'mojiscript/list/map'
    import range from 'mojiscript/list/range'
    import sleep from 'mojiscript/threading/sleep'
    
    const fetchJson = pipe ([
      axios.get,
      response => response.data
    ]) 
    
    const fetchLogWait = pipe ([
      id => fetchJson (`https://swapi.co/api/people/${id}`),
      log,
      sleep (1000)
    ])
    
    const main = pipe ([
      ({ start, end }) => range (start) (end + 1),
      map(fetchLogWait),
    ])
    
    main ({ start: 1, end: 3 })
    
    지금, 이 코드는 이미 매우 무미건조해졌다!

    for 사이클에서 시간 초과 설정


    현재 이 문제를 보지 못했다면 많은 자바스크립트 인터뷰에서 이 문제를 볼 수 있습니다.코드가 예상대로 실행되지 않았습니다.출력은 무엇입니까?
    for (var i = 1; i < 6; i++) {
      setTimeout(() => console.log(i), 1000)
    }
    
    만약 그것이 1초를 멈추고 한 번에 5개의 6을 출력할 것이라고 생각하지 못했다면, 당신은 틀렸다.pipe과 Mojiscript의 map을 사용하여 동일한 프로그램을 작성합니다.이외에도 이 기능은 예상대로 작동하며, 매번 출력하기 전에 1초의 정지로 1부터 5까지 인쇄됩니다.
    const sleepThenLog = pipe ([
      sleep (1000),
      log
    ])
    
    const main = pipe ([
      range (1) (6),
      map (sleepThenLog)
    ])
    
    더 하고 싶어요?

    구글 얘기.

  • Callback Hell
  • Comma Operator
  • Function Composition
  • Ramda
  • MojiScript
  • 총결산


    sleep를promise 스타일로 변환하는 함수는 비동기 코드 실행 방식의 추가 옵션을 제공합니다.
    Ramda의 pipeP 또는 Mojiscript의 pipe은 때때로 Promises 또는 async/await보다 더 깨끗하다.
    비동기식 매핑 기능이 강력합니다.
    아래에서 지적한 경고는 이런 실현은 취소를 허락하지 않는다는 것이다.따라서 clearTimeout이 필요한 경우 이 함수를 수정해야 합니다.
    제 글은 모두 기능성이 강한 자바스크립트입니다. 더 필요하시면 저를 따라오세요. 아니면 트위터로 오세요!
    내 기타 기사 읽기:
    How I rediscovered my love for JavaScript after throwing 90% of it in the trash

    좋은 웹페이지 즐겨찾기