비동기 처리는 비동기 절차에 따라 문제를 처리하는 것입니다. 비동기 처리와 동기 처리는 반대이며 이를 생성하는 것은 멀티스레딩 또는 멀티프로세스입니다. 비동기 처리의 장점은 장치 활용도를 높여 매크로 수준에서 프로그램 작동 효율성을 향상시키는 것이지만, 단점은 충돌하는 작업과 더티 데이터 읽기가 발생하기 쉽다는 것입니다. 이번 글에서는 자바스크립트의 비동기 처리에 대해 알려드리겠습니다.
JavaScript 세계에서는 모든 코드가 단일 스레드에서 실행됩니다. 이 "결함"으로 인해 JavaScript의 모든 네트워크 작업과 브라우저 이벤트는 비동기적으로 실행되어야 합니다. 콜백 함수를 사용하여 비동기 실행을 구현할 수 있습니다
비동기 작업은 미래의 특정 시점에 함수 호출을 트리거합니다
주요 비동기 처리 솔루션에는 주로 콜백 함수(CallBack), Promise, Generator 함수, async/await가 포함됩니다.
1. 콜백 함수(CallBack)
이것이 비동기 프로그래밍의 가장 기본적인 방법입니다
비동기적으로 데이터를 가져오는 데 사용되는 getData 메서드가 있다고 가정해 보겠습니다. 첫 번째 매개 변수는 요청한 URL 주소이고 두 번째 매개 변수는 다음과 같습니다. 콜백 함수는 다음과 같습니다.
function getData(url, callBack){ // 模拟发送网络请求 setTimeout(()=> { // 假设 res 就是返回的数据 var res = { url: url, data: Math.random() } // 执行回调,将数据作为参数传递 callBack(res) }, 1000) }
미리 시나리오를 설정했습니다. 서버에 세 번 요청한다고 가정합니다. 각 요청은 다음과 같이 이전 요청의 결과에 따라 달라집니다. 위 코드에서 첫 번째 요청의 URL 주소는 /page/1?param=123이고 반환된 결과는 res1입니다.
두 번째 요청의 URL 주소는 /page/2?param=${res1.data}이며, 이는 첫 번째 요청의 res1.data에 따라 달라지며 반환된 결과는 res2`입니다.
세 번째 요청의 URL 주소는 /page/3?param=${res2.data}이며 이는 두 번째 요청의 res2.data에 따라 달라지며 반환된 결과는 res3입니다.
다음 요청은 이전 요청의 결과에 따라 달라지므로 이전 요청의 콜백 함수 내에 다음 요청만 작성할 수 있으므로 흔히 말하는 콜백 지옥이 형성됩니다.
2. 게시/구독
작업이 완료되면 신호가 신호 센터에 "게시"되고 다른 작업은 신호 센터에 "구독"될 수 있다고 가정합니다. 신호를 통해 언제 실행을 시작할 수 있는지 알 수 있습니다. 이를 "게시-구독 패턴"이라고 하며 "관찰자 패턴"(관찰자 패턴)이라고도 합니다. 다음은 Ben Alman의 Tiny Pub/Sub입니다. jQuery용 플러그인
먼저 f2는 "시그널 센터" jQuery done "signal
getData('/page/1?param=123', (res1) => { console.log(res1) getData(`/page/2?param=${res1.data}`, (res2) => { console.log(res2) getData(`/page/3?param=${res2.data}`, (res3) => { console.log(res3) }) }) })
jQuery.subscribe("done", f2);
를 구독합니다. 이 방법의 특성은 "이벤트 수신"과 유사하지만 후자보다 훨씬 낫습니다. "메시지 센터"를 보고 프로그램 운영을 모니터링하여 신호 수와 각 신호의 구독자 수를 확인할 수 있기 때문입니다.
3. Promise
Promise는 콜백 함수 및 이벤트와 같은 기존 솔루션보다 더 합리적이고 강력합니다.
Promise는 단순히 특정 이벤트 결과를 저장하는 컨테이너입니다. (보통 비동기 작업) 미래에 종료됩니다. 구문론적으로 Promise는 비동기 작업에 대한 메시지를 얻을 수 있는 개체입니다. Promise는 통합 API를 제공하며 다양한 비동기 작업을 동일한 방식으로 처리할 수 있습니다. 간단히 말해서 각 비동기 작업은 콜백 함수를 지정할 수 있는 then 메서드가 있는 Promise 개체를 반환한다는 것입니다.
이제 Promise를 사용하여 위 사례를 다시 구현합니다. 먼저 비동기 데이터 요청 메서드를 Promise로 캡슐화해야 합니다
f1进行如下改写 function f1(){ setTimeout(function(){ // f1的任务代码 jQuery.publish("done"); }, 1000);} jQuery.publish("done") 的意思是, f1 执行完成后,向”信号中心 "jQuery 发布 "done" 信号,从而引发f2的执行。 此外,f2完成执行后,也可以取消订阅( unsubscribe ) jQuery.unsubscribe("done", f2);
그런 다음 요청 코드는 다음과 같이 작성해야 합니다
function getDataAsync(url){ return new Promise((resolve, reject) => { setTimeout(()=> { var res = { url: url, data: Math.random() } resolve(res) }, 1000) }) }
그런 다음 메서드는 새로운 Promise 객체를 반환합니다. , 그리고 연결된 메소드 호출은 콜백 콜백 지옥
을 방지하지만 완벽하지는 않습니다. 예를 들어, then 문을 많이 추가해야 하는 경우 여전히 각 then에 대해 콜백을 작성해야 합니다.
예를 들어 시나리오가 더 복잡하다면 각 후속 요청은 이전 요청의 결과뿐만 아니라 모든 이전 요청의 결과에 따라 달라지므로 더 복잡해집니다. 더 잘하기 위해 async/await를 사용하여 구현하는 방법을 살펴보겠습니다.
4. async/await
getDataAsync 메소드는 다음과 같이 변경되지 않습니다
getDataAsync('/page/1?param=123') .then(res1=> { console.log(res1) return getDataAsync(`/page/2?param=${res1.data}`) }) .then(res2=> { console.log(res2) return getDataAsync(`/page/3?param=${res2.data}`) }) .then(res3=> { console.log(res3) })
비즈니스 코드는 다음과 같습니다
async 함수 getData(){ var res1 = wait getDataAsync('/page/1?param=123') console.log(res1) var res2 = wait getDataAsync(`/page/2?param=${res1.data} `) console .log(res2) var res3 = wait getDataAsync(`/page/2?param=${res2.data}`) console.log(res3)
}asyncawait를 사용하는 것은 다음과 같다는 것을 알 수 있습니다. 동기 코드 작성
Promise를 비교해보면 어떤 느낌인가요? 매우 명확하지만 async/await는 Promise를 기반으로 합니다. 왜냐하면 async로 장식된 메서드는 궁극적으로 Promise를 반환하기 때문입니다. 실제로 async/await는 비동기 구문 설탕을 처리하기 위해 Generator 함수를 사용하는 것으로 볼 수 있습니다. 제너레이터 함수는 비동기 처리를 처리합니다
5. 제너레이터
먼저 비동기 함수는 여전히
function getDataAsync(url){ return new Promise((resolve, reject) => { setTimeout(()=> { var res = { url: url, data: Math.random() } resolve(res) }, 1000) }) }
제너레이터 함수를 사용하는 방법은 이렇게 작성하면 됩니다
function getDataAsync(url){ return new Promise((resolve, reject) => { setTimeout(()=> { var res = { url: url, data: Math.random() } resolve(res) }, 1000) }) }
그런 다음 단계별로 실행해 보겠습니다
var g = getData() g.next().value.then(res1=> { g.next(res1).value.then(res2=> { g.next(res2).value.then(()=> { g.next() }) }) })
上面的代码,我们逐步调用遍历器的 next() 方法,由于每一个 next() 方法返回值的 value 属性为一个 Promise 对象
所以我们为其添加 then 方法, 在 then 方法里面接着运行 next 方法挪移遍历器指针,直到 Generator 函数运行完成,实际上,这个过程我们不必手动完成,可以封装成一个简单的执行器
function run(gen){ var g = gen() function next(data){ var res = g.next(data) if (res.done) return res.value res.value.then((data) => { next(data) }) } next() }
run 方法用来自动运行异步的 Generator 函数,其实就是一个递归的过程调用的过程。这样我们就不必手动执行 Generator 函数了。 有了 run 方法,我们只需要这样运行 getData 方法
run(getData)
这样,我们就可以把异步操作封装到 Generator 函数内部,使用 run 方法作为 Generator 函数的自执行器,来处理异步。其实我们不难发现, async/await 方法相比于 Generator 处理异步的方式,有很多相似的地方,只不过 async/await 在语义化方面更加明显,同时 async/await 不需要我们手写执行器,其内部已经帮我们封装好了,这就是为什么说 async/await 是 Generator 函数处理异步的语法糖了
以上内容就是关于JavaScript中的异步处理,希望能帮助到大家。
相关推荐:
위 내용은 JavaScript의 비동기 처리 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!