Promise Chains는 좀 굉장합니다.
21732 단어 functionalasyncjavascriptpromise
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
을 지적했습니다. 여기 스니펫이 업데이트되었습니다.사용자
이후 수정된 두 번째 예에서 오타(주석 참조)를 지적했습니다.
Reference
이 문제에 관하여(Promise Chains는 좀 굉장합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/bennypowers/promise-chains-are-kinda-awesome-273o텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)