웹 프론트엔드 JS 튜토리얼 JS 비동기 기능을 최적화하는 방법

JS 비동기 기능을 최적화하는 방법

May 30, 2018 am 10:16 AM
async javascript 최적화

이번에는 js async 기능을 최적화하는 방법과 js async 기능을 최적화할 때 주의 사항이 무엇인지 보여드리겠습니다. 다음은 실제 사례입니다.

먼저 Promise를 이해해야 합니다

Promise는 async/await를 사용하는 기본이므로 Promise가 무엇을 하는지 먼저 이해해야 합니다

Promise는 콜백 지옥을 해결하는 데 도움이 되는 좋은 기능이며, 비동기화를 할 수 있습니다. 프로세스가 더욱 명확해집니다.

Error-first-callback을 Promise로 변환하는 간단한 예:

const fs = require('fs')
function readFile (fileName) {
 return new Promise((resolve, reject) => {
  fs.readFile(fileName, (err, data) => {
   if (err) reject(err)
   resolve(data)
  })
 })
}
readFile('test.log').then(data => {
 console.log('get data')
}, err => {
 console.error(err)
})
로그인 후 복사

함수를 호출하여 Promise 인스턴스를 반환하고 인스턴스화 프로세스 중에 파일을 읽습니다. 파일 읽기를 위한 콜백이 트리거되면 then을 사용하여 다음을 수행합니다. Promise 상태, 해결 또는 거부 상태의 변경 사항을 모니터링합니다. 첫 번째 콜백은 해결 처리를 위한 것이고 두 번째 콜백은 거부 처리를 위한 것입니다.

async와 Promise의 관계

async 함수는 Promise 인스턴스를 반환하는 단축 함수와 동일합니다. 효과는 다음과 같습니다.

function getNumber () {
 return new Promise((resolve, reject) => {
  resolve(1)
 })
}
// =>
async function getNumber () {
 return 1
}
로그인 후 복사

둘은 사용 시 완전히 동일하며 이후에 사용할 수 있습니다. getNumber 함수를 호출한 다음 반환 값을 모니터링합니다. 그리고 async에 해당하는 wait 구문을 사용하는 방법:

getNumber().then(data => {
 // got data
})
// =>
let data = await getNumber()
로그인 후 복사

await를 실행하면 expression 뒤에 있는 Promise 실행 결과를 얻게 됩니다. 이는 콜백 결과를 얻기 위해 then을 호출하는 것과 동일합니다. 추신: 비동기/대기 지원이 그다지 높지 않은 경우 모든 사람은 유사한 효과를 얻기 위해 co와 유사한 일부 라이브러리와 결합된 생성기/수율을 사용하기로 선택했습니다.

async 함수 코드 실행은 동기식이며 결과 반환은 비동기식입니다

비동기 함수 이는 항상 Promise의 인스턴스를 반환하므로 비동기 함수를 호출할 때 내부 코드가 new Promise에 있음을 이해할 수 있으며 최종 반환 작업은 Resolve를 호출할 때와 동일합니다. Promise:

async function getNumber () {
 console.log('call getNumber()')
 return 1
}
getNumber().then(_ => console.log('resolved'))
console.log('done')
// 输出顺序:
// call getNumber()
// done
// resolved
로그인 후 복사

Promise 내부의 Promise는 소화될 것입니다

즉, 다음과 같은 코드가 있다면:

function getNumber () {
 return new Promise(resolve => {
  resolve(Promise.resolve(1))
 })
}
getNumber().then(data => console.log(data)) // 1
로그인 후 복사

위에서 말한 내용을 따르면 데이터를 얻을 수 있습니다. 또 다른 Promise 인스턴스인 Resolve에 전달된 값입니다.
그러나 실제로는 반환 값을 직접 얻습니다. 1. 즉, Promise가 Promise에서 반환되면 프로그램은 실제로 이 Promise를 실행하는 데 도움이 되며 내부 Promise 상태가 변경될 때와 같은 콜백을 트리거합니다. .
흥미로운 점:

function getNumber () {
 return new Promise(resolve => {
  resolve(Promise.reject(new Error('Test')))
 })
}
getNumber().catch(err => console.error(err)) // Error: Test
로그인 후 복사

Resolve에서 거부를 전달하면 직접 catch를 사용하여 외부에서 모니터링할 수 있습니다.
이 방법은 비동기 함수에서 예외를 발생시키는 데 자주 사용됩니다.비동기 함수에서 예외를 발생시키는 방법:

async function getNumber () {
 return Promise.reject(new Error('Test'))
}
try {
 let number = await getNumber()
} catch (e) {
 console.error(e)
}
로그인 후 복사

await 키워드를 잊지 마세요

await 키워드 추가를 잊어버린 경우, 코드 수준 아니요 오류가 보고되지만 우리가 받는 반환 값은 Promise입니다

let number = getNumber()
console.log(number) // Promise
로그인 후 복사
사용할 때 wait 키워드를 꼭 기억하세요

let number = await getNumber()
console.log(number) // 1
로그인 후 복사
로그인 후 복사
모든 곳에 wait를 추가할 필요는 없습니다

코드 실행 중에 다음이 있습니다. 현재 모든 비동기 작업에 대기를 추가할 필요는 없습니다. 예를 들어 파일에 대한 작업은 다음과 같습니다.

fs의 모든 API가 우리에 의해 Promise 버전으로 변환되었다고 가정합니다.

let number = await getNumber()
console.log(number) // 1
로그인 후 복사
로그인 후 복사
await를 통해 파일을 연 다음 파일을 두 번 씁니다.

그러나 두 파일 쓰기 작업 전에 wait 키워드를 추가하지 않았습니다.

이것은 중복되기 때문에 이 파일에 텍스트 한 줄을 쓰고 싶다는 것을 API에 알리기만 하면 됩니다. 순서는 자연스럽게 fs에 의해 제어됩니다.
그런 다음 마지막에 대기를 사용하여 파일을 닫습니다.
위의 쓰기 프로세스를 실행하면 닫기 콜백이 트리거되지 않습니다.
즉, 콜백이 트리거된다는 것은 위의 두 가지 쓰기 단계가 완료되었음을 의미합니다.

관련되지 않은 여러 비동기 함수 호출을 병합

이제 사용자의 아바타와 사용자 세부 정보를 얻으려는 경우(정상적인 상황에서는 나타나지 않을 것 같지만 두 인터페이스입니다)

async function getUser () {
 let avatar = await getAvatar()
 let userInfo = await getUserInfo()
 return {
  avatar,
  userInfo
 }
}
로그인 후 복사

这样的代码就造成了一个问题,我们获取用户信息的接口并不依赖于头像接口的返回值。
 但是这样的代码却会在获取到头像以后才会去发送获取用户信息的请求。
 所以我们对这种代码可以这样处理:

async function getUser () {
 let [avatar, userInfo] = await Promise.all([getAvatar(), getUserInfo()])
 return {
  avatar,
  userInfo
 }
}
로그인 후 복사

这样的修改就会让getAvatar与getUserInfo内部的代码同时执行,同时发送两个请求,在外层通过包一层Promise.all来确保两者都返回结果。

让相互没有依赖关系的异步函数同时执行

一些循环中的注意事项

forEach

当我们调用这样的代码时:

async function getUsersInfo () {
 [1, 2, 3].forEach(async uid => {
  console.log(await getUserInfo(uid))
 })
}
function getuserInfo (uid) {
 return new Promise(resolve => {
  setTimeout(_ => resolve(uid), 1000)
 })
}
await getUsersInfo()
로그인 후 복사

这样的执行好像并没有什么问题,我们也会得到1、2、3三条log的输出,但是当我们在await getUsersInfo()下边再添加一条console.log('done')的话,就会发现:

 我们会先得到done,然后才是三条uid的log,也就是说,getUsersInfo返回结果时,其实内部Promise并没有执行完。
 这是因为forEach并不会关心回调函数的返回值是什么,它只是运行回调。

不要在普通的for、while循环中使用await

使用普通的for、while循环会导致程序变为串行:

for (let uid of [1, 2, 3]) {
 let result = await getUserInfo(uid)
}
로그인 후 복사

这样的代码运行,会在拿到uid: 1的数据后才会去请求uid: 2的数据

--------------------------------------------------------------------------------

关于这两种问题的解决方案:

目前最优的就是将其替换为map结合着Promise.all来实现:

await Promise.all([1, 2, 3].map(async uid => await getUserInfo(uid)))
로그인 후 복사
로그인 후 복사

这样的代码实现会同时实例化三个Promise,并请求getUserInfo

P.S. 草案中有一个await*,可以省去Promise.all

await Promise.all([1, 2, 3].map(async uid => await getUserInfo(uid)))
로그인 후 복사
로그인 후 복사

P.S. 为什么在使用Generator+co时没有这个问题

在使用koa1.x的时候,我们直接写yield [].map是不会出现上述所说的串行问题的看过co源码的小伙伴应该都明白,里边有这么两个函数(删除了其余不相关的代码):

function toPromise(obj) {
 if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
 return obj;
}
function arrayToPromise(obj) {
 return Promise.all(obj.map(toPromise, this));
}
로그인 후 복사

co是帮助我们添加了Promise.all的处理的(膜拜TJ大佬)。

总结

总结一下关于async函数编写的几个小提示:

1.使用return Promise.reject()在async函数中抛出异常
2.让相互之间没有依赖关系的异步函数同时执行
3.不要在循环的回调中/for、while循环中使用await,用map来代替它

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样使用垃圾回收器

怎样使用Nodejs内存治理

怎样使用vue的toast弹窗组件

위 내용은 JS 비동기 기능을 최적화하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. 크로스 플레이가 있습니까?
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

심층 해석: Laravel이 달팽이처럼 느린 이유는 무엇입니까? 심층 해석: Laravel이 달팽이처럼 느린 이유는 무엇입니까? Mar 07, 2024 am 09:54 AM

Laravel은 널리 사용되는 PHP 개발 프레임워크이지만 달팽이처럼 느리다는 비판을 받기도 합니다. Laravel의 만족스럽지 못한 속도의 정확한 원인은 무엇입니까? 이 기사에서는 Laravel이 달팽이처럼 느린 이유를 여러 측면에서 심층적으로 설명하고 이를 특정 코드 예제와 결합하여 독자가 이 문제를 더 깊이 이해할 수 있도록 돕습니다. 1. ORM 쿼리 성능 문제 Laravel에서 ORM(Object Relational Mapping)은 매우 강력한 기능입니다.

Golang의 gc 최적화 전략에 대한 토론 Golang의 gc 최적화 전략에 대한 토론 Mar 06, 2024 pm 02:39 PM

Golang의 가비지 수집(GC)은 항상 개발자들 사이에서 뜨거운 주제였습니다. 빠른 프로그래밍 언어인 Golang에 내장된 가비지 컬렉터는 메모리를 매우 잘 관리할 수 있지만, 프로그램의 크기가 커질수록 일부 성능 문제가 발생하는 경우가 있습니다. 이 기사에서는 Golang의 GC 최적화 전략을 살펴보고 몇 가지 구체적인 코드 예제를 제공합니다. Golang의 가비지 수집 Golang의 가비지 수집기는 동시 마크 스윕(concurrentmark-s)을 기반으로 합니다.

Laravel 성능 병목 현상 디코딩: 최적화 기술이 완전히 공개되었습니다! Laravel 성능 병목 현상 디코딩: 최적화 기술이 완전히 공개되었습니다! Mar 06, 2024 pm 02:33 PM

Laravel 성능 병목 현상 디코딩: 최적화 기술이 완전히 공개되었습니다! 인기 있는 PHP 프레임워크인 Laravel은 개발자에게 풍부한 기능과 편리한 개발 경험을 제공합니다. 그러나 프로젝트 규모가 커지고 방문 횟수가 늘어나면서 성능 병목 현상에 직면할 수도 있습니다. 이 기사에서는 개발자가 잠재적인 성능 문제를 발견하고 해결하는 데 도움이 되는 Laravel 성능 최적화 기술을 탐구합니다. 1. Eloquent 지연 로딩을 사용한 데이터베이스 쿼리 최적화 Eloquent를 사용하여 데이터베이스를 쿼리할 때 다음을 피하세요.

C++ 프로그램 최적화: 시간 복잡도 감소 기술 C++ 프로그램 최적화: 시간 복잡도 감소 기술 Jun 01, 2024 am 11:19 AM

시간 복잡도는 입력 크기를 기준으로 알고리즘의 실행 시간을 측정합니다. C++ 프로그램의 시간 복잡성을 줄이는 팁에는 데이터 저장 및 관리를 최적화하기 위한 적절한 컨테이너(예: 벡터, 목록) 선택이 포함됩니다. Quick Sort와 같은 효율적인 알고리즘을 활용하여 계산 시간을 단축합니다. 여러 작업을 제거하여 이중 계산을 줄입니다. 불필요한 계산을 피하려면 조건부 분기를 사용하세요. 이진 검색과 같은 더 빠른 알고리즘을 사용하여 선형 검색을 최적화합니다.

Laravel 성능 병목 현상 공개: 최적화 솔루션 공개! Laravel 성능 병목 현상 공개: 최적화 솔루션 공개! Mar 07, 2024 pm 01:30 PM

Laravel 성능 병목 현상 공개: 최적화 솔루션 공개! 인터넷 기술이 발전함에 따라 웹사이트와 애플리케이션의 성능 최적화가 점점 더 중요해지고 있습니다. 널리 사용되는 PHP 프레임워크인 Laravel은 개발 프로세스 중에 성능 병목 현상에 직면할 수 있습니다. 이 문서에서는 Laravel 애플리케이션이 직면할 수 있는 성능 문제를 살펴보고 개발자가 이러한 문제를 더 잘 해결할 수 있도록 몇 가지 최적화 솔루션과 특정 코드 예제를 제공합니다. 1. 데이터베이스 쿼리 최적화 데이터베이스 쿼리는 웹 애플리케이션의 일반적인 성능 병목 현상 중 하나입니다. 존재하다

WIN7 시스템의 시작 항목을 최적화하는 방법 WIN7 시스템의 시작 항목을 최적화하는 방법 Mar 26, 2024 pm 06:20 PM

1. 바탕화면에서 키조합(Win키 + R)을 눌러 실행창을 연 후, [regedit]를 입력하고 Enter를 눌러 확인하세요. 2. 레지스트리 편집기를 연 후 [HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorer]를 클릭하여 확장한 다음 디렉터리에 Serialize 항목이 있는지 확인합니다. 없으면 탐색기를 마우스 오른쪽 버튼으로 클릭하고 새 항목을 생성한 다음 이름을 Serialize로 지정합니다. 3. 그런 다음 직렬화를 클릭한 다음 오른쪽 창의 빈 공간을 마우스 오른쪽 버튼으로 클릭하고 새 DWORD(32) 비트 값을 만들고 이름을 Star로 지정합니다.

Vivox100s 매개변수 구성 공개: 프로세서 성능을 최적화하는 방법은 무엇입니까? Vivox100s 매개변수 구성 공개: 프로세서 성능을 최적화하는 방법은 무엇입니까? Mar 24, 2024 am 10:27 AM

Vivox100s 매개변수 구성 공개: 프로세서 성능을 최적화하는 방법은 무엇입니까? 오늘날 급속한 기술 발전 시대에 스마트폰은 우리 일상생활에서 없어서는 안 될 부분이 되었습니다. 스마트폰의 중요한 부분인 프로세서의 성능 최적화는 휴대폰의 사용자 경험과 직접적인 관련이 있습니다. 주목받는 스마트폰인 Vivox100s의 매개변수 구성은 많은 관심을 끌었으며, 특히 프로세서 성능의 최적화는 사용자들의 많은 관심을 끌었습니다. 휴대폰의 "두뇌"인 프로세서는 휴대폰의 실행 속도에 직접적인 영향을 미칩니다.

PHP 기능의 비효율성을 해결하는 방법은 무엇입니까? PHP 기능의 비효율성을 해결하는 방법은 무엇입니까? May 02, 2024 pm 01:48 PM

PHP 기능 효율성을 최적화하는 5가지 방법: 불필요한 변수 복사를 방지합니다. 변수 복사를 방지하려면 참조를 사용하세요. 반복되는 함수 호출을 피하세요. 인라인 단순 함수. 배열을 사용하여 루프 최적화.

See all articles