Promise Chains는 좀 굉장합니다.

아, 약속 때문에 오셨어요? 예, 잠시 후에 설명하겠습니다. 하지만 먼저 Trace라는 제 친구를 소개하겠습니다.

const trace = tag => x =>
  console.log(tag, x) || x;


우리는 몇 년 전에 이 잼@drBoolean에서 만났고 꽤 잘 맞았습니다. 저는 우리가 공통점이 많다는 것을 깨달았습니다. 우리 둘 다 강한 정체성을 가지고 있지만 요청을 받았을 때 측면에서 약간의 변화를 일으키는 것을 두려워하지 않습니다. 아이도 비열한 카레를 만듭니다.

trace :: Show t => t -> a -> a


트레이스는 당신이 그를 어디에 두든 신경쓰지 않고 자신의 일을 하는 것만으로도 행복합니다. 일종의 흐름과 함께 간다, 약속!

['a', 'b', 'c']
  .map(trace('what do we have here...'))

// what do we have here ... a
// what do we have here ... b
// what do we have here ... c

어레이에 매핑됨Array#Map

const handleAsJson = resp => resp.json()

fetch(`/users`)
  .then(handleAsJson)
  .then(trace('all users: '))

// all users: [{ id: 1, isAdmin: false }, { id: 2, isAdmin: true }]

Promise#then으로 Promise에 매핑됨

추적은 언뜻 보기에 사소하고 심지어 경박해 보일 수도 있습니다. 그러나 그 단순함은 그 힘의 기초가 됩니다. 더 크고 더 큰 계산으로 쉽게 결합되는 일종의 단순하고 원자적이며 단일 목적의 다중 사용 기능입니다.

어쨌든, 나는 여기서 옆길로 가고 있습니다.

그래서 어느 날 트레이스와 나는 디너 파티를 열기로 했다. 작업을 짧은 할 일 목록으로 나누었습니다.
  • 게스트 목록 작성
  • 초대장 보내기
  • 재료 주문하기
  • 앙트레 요리하기
  • 저녁 식사 제공

  • const handleAsJson = resp => resp.json()
    const map = f => xs => xs.map(f)
    const all = Promise.all.bind(Promise)
    
    const fetchGuests = () => fetch('/friends')
    const fetchShoppingList = () => fetch('/shopping-list')
    const order = item => fetch(`https://groceries.for.you/order/${item}`)
    const invite = body => to =>
      fetch(`/sendmail?to="${encodeURIComponent(to)}`, { method: 'POST', body })
    
    const getEmail = ({ email }) => email
    const cook = xs => xs.reduce(fricassee, 'a delicious ')
    const serve = dish => alert(`${dish} is served!`)
    const fricassee = (a, x, i, {length}) =>
      `${a}-${x}${i === length - 1 ? ' fricassee' : ''}`
    
    function party() {
      return fetchGuests()
        .then(handleAsJson)      // Promise<[person]>
        .then(map(getEmail))     // Promise<[string]>
        .then(map(invite))       // Promise<[Response]>
        .then(all)               // Promise<[invitation]>
        .then(fetchShoppingList) // discard previous result, as `fetchShoppingList` takes no arguments.
        .then(handleAsJson)      // Promise<[item]>
        .then(map(order))        // Promise<[Promise<order>]>
        .then(all)               // Promise<[order]>
        .then(cook)              // Promise<Fricasee>
        .then(serve)             // et voila
    }
    


    나에게 이런 종류의 위에서 아래로 왼쪽에서 오른쪽으로의 흐름은 읽기 쉽고 아름답습니다. 한 번에 한 가지, 즉 각 then 호출에서 전달하는 함수만 추적하면 됩니다.

    그러나이 흐름은 VS-Code의 의견 omatic Lightbulb of Truth ™ ️에 위배됩니다.



    대안을 고려하십시오.

    async function party() {
      const guestsResponse = await fetchGuests()
      const guests = await guestsResponse.json()
      const emails = guests.map(getEmail)
      const inviteResponses = emails.map(invite)
      const listResponse = fetchShoppingList()
      const list = listResponse.json()
      const orderPromises = list.map(order)
      const orderResponses = Promise.all(orderPromises)
      const order = orderResponses.map(handleAsJson)
      const dish = cook(order)
      return serve(dish)
    }
    


    레드몬드에서 우리의 문체 대군주를 달래기 위해 얼마나 많은 상태, 얼마나 많은 진술, 얼마나 많은 정신적 실행이 필요할 것입니까?

    폐쇄를 통한 양도



    식이 요구와 관련하여 각 사용자를 개별적으로 제공할 수 있도록 사용자를 추적해야 한다고 가정해 보겠습니다. 클로저로 그렇게 할 수 있습니다. 지금은 클로저에 대한 혼란스러운 기술적 정의에 들어갈 때가 아닙니다. 지금은 함수가 자신의 매개변수에 액세스할 수 있다고 말할 것입니다.

    const all = Promise.all.bind(Promise)
    
    const constant = x => () => x
    
    const not = p => x => !p(x)
    
    const fanout = (f, g) => x => [f(x), g(x)]
    const merge = f => ([x, y]) => f(x, y)
    
    const bimap = (f, g) => ([xs, ys]) => [xs.map(f), ys.map(g)]
    
    const serve = dish => guest => alert(`${guest} has been served ${dish}!`)
    
    function party() {
      return fetchShoppingList()
        .then(handleAsJson)
        .then(map(order))
        .then(cook)
        .then(dish => orderDietDishes() // no closing `)`, so dish stays in closure
        .then(handleAsJson)
        .then(dietDish => fetchGuests() // no closing `)`, so dietDish stays in closure
        .then(handleAsJson)
        .then(users => Promise.resolve(users)
        .then(map(getEmail))
        .then(map(invite))
        .then(all)
        .then(constant(users)))
        .then(fanout(filter(hasDiet), filter(not(hasDiet))))
        .then(merge(bimap(serve(dietDish), serve(dish)))))) // end closures from above
    }
    


    주의: 이 인위적인 예에서는 요점을 설명하기 위해 클로저를 사용했지만 실제로는 팬아웃 및 병합을 위해 배열 대신 crocks의 데이터 유형을 사용하거나 상태를 유지하기 위해 POJO를 전달할 수 있습니다. await 를 사용하고 const 에 할당할 수도 있지만 매번 포장을 풀면서 아기를 목욕물과 함께 버리지는 않을 것입니다. 하나의. 약속하다. 호출 사이트에서.

    요약



    이름이 잘 지정되고 단순하며 구성 가능한 일급 함수를 전달하면 산문처럼 읽히는 코드가 생성됩니다. 이와 같이 계산 단계를 분리하면 독자의 정신적 파싱에 대한 인지 부하를 함수 구현으로 미루고 프로그램을 더 읽기 쉽고 유지 관리하기 쉽게 만듭니다.

    튜플로 팬아웃하고 이진 함수와 병합하는 것과 같은 기술은 '병렬' 계산을 수행하거나 누적된 상태를 순수 함수에 전달하는 데 매우 적합합니다. 특히 클로저의 양을 관리하기 어려울 때 비동기 함수도 제자리에 있지만 모든 마지막 호출.then을 대체해서는 안 됩니다.

    약속해줘!



    따라서 Promise Chain은 놀랍고 코드를 더 읽기 쉽게 만들고 가장 유용한 방식으로 사용하는 한 더 나은 소프트웨어에 기여합니다. 다음에 얻을 기회는 작은 전구에 "고마워요"라고 말하세요. 앱에서 Promise Chain을 구성하고 자체 문서화되는 모듈식 코드를 즐기세요.

    감사의 말과 정오표



    이전 버전은 Promise.all 퍼스트 클래스 즉 urls.map(fetch).then(Promise.all) 덕분에
    첫 번째 클래스를 통과하려면 바인딩해야 함Promise.all을 지적했습니다. 여기 스니펫이 업데이트되었습니다.

    사용자
    이후 수정된 두 번째 예에서 오타(주석 참조)를 지적했습니다.

    좋은 웹페이지 즐겨찾기