Promise 및 Async/await 함수는 모두 JavaScript의 비동기 문제를 해결하는 데 사용됩니다. 그렇다면 두 함수의 차이점은 무엇인가요? 다음 기사에서는 Promise, Generator 및 Async의 차이점을 소개합니다. 도움이 되길 바랍니다.
우리는 JavaScript의 비동기 문제를 해결하기 위해 Promise
와 Async/await
함수가 사용된다는 것을 알고 있습니다. >Promise는 비동기 처리를 처리하고, Generator
는 비동기 처리를 처리하고, Async/await
는 비동기 처리를 처리합니다. 각 기술 업데이트를 통해 JavaScript는 비동기 처리를 보다 효율적으로 처리합니다. 현재의 관점에서 볼 때 Async/await
는 비동기 처리를 위한 궁극적인 솔루션으로 간주되어 JS의 비동기 처리를 점점 더 동기 작업과 유사하게 만듭니다. 비동기 프로그래밍의 가장 높은 상태는 비동기 여부에 대해 걱정할 필요가 없다는 것입니다. Promise
与Async/await
函数都是用来解决JavaScript中的异步问题的,从最开始的回调函数处理异步,到Promise
处理异步,到Generator
处理异步,再到Async/await
处理异步,每一次的技术更新都使得JavaScript处理异步的方式更加优雅,从目前来看,Async/await
被认为是异步处理的终极解决方案,让JS的异步处理越来越像同步任务。异步编程的最高境界,就是根本不用关心它是不是异步。
异步解决方案的发展历程
1.回调函数
从早期的Javascript代码来看,在ES6诞生之前,基本上所有的异步处理都是基于回调函数函数实现的,你们可能会见过下面这种代码:
ajax('aaa', () => { // callback 函数体 ajax('bbb', () => { // callback 函数体 ajax('ccc', () => { // callback 函数体 }) }) })
没错,在ES6出现之前,这种代码可以说是随处可见。它虽然解决了异步执行的问题,可随之而来的是我们常听说的回调地狱问题:
- 没有顺序可言:嵌套函数执行带来的是调试困难,不利于维护与阅读
- 耦合性太强:一旦某一个嵌套层级有改动,就会影响整个回调的执行
所以,为了解决这个问题,社区最早提出和实现了Promise
,ES6将其写进了语言标准,统一了用法。
2.Promise
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它就是为了解决回调函数产生的问题而诞生的。
有了Promise
对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
所以上面那种回调函数的方式我们可以改成这样:(前提是ajax已用Promise包装)
ajax('aaa').then(res=>{ return ajax('bbb') }).then(res=>{ return ajax('ccc') })
通过使用Promise
来处理异步,比以往的回调函数看起来更加清晰了,解决了回调地狱的问题,Promise
的then
的链式调用更能让人接受,也符合我们同步的思想。
但Promise也有它的缺点:
- Promise的内部错误使用
try catch
捕获不到,只能只用then
的第二个回调或catch
来捕获
let pro try{ pro = new Promise((resolve,reject) => { throw Error('err....') }) }catch(err){ console.log('catch',err) // 不会打印 } pro.catch(err=>{ console.log('promise',err) // 会打印 })
- Promise一旦新建就会立即执行,无法取消
之前写过一篇,讲解了Promise如何使用以及内部实现原理。对Promise还不太理解的同学可以看看~
从如何使用到如何实现一个Promise
https://juejin.cn/post/7051364317119119396
3.Generator
Generator
函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。Generator
函数将 JavaScript 异步编程带入了一个全新的阶段。
声明
与函数声明类似,不同的是function
关键字与函数名之间有一个星号,以及函数体内部使用yield
表达式,定义不同的内部状态(yield
在英语里的意思就是“产出”)。
function* gen(x){ const y = yield x + 6; return y; } // yield 如果用在另外一个表达式中,要放在()里面 // 像上面如果是在=右边就不用加() function* genOne(x){ const y = `这是第一个 yield 执行:${yield x + 1}`; return y; }
执行
const g = gen(1); //执行 Generator 会返回一个Object,而不是像普通函数返回return 后面的值 g.next() // { value: 7, done: false } //调用指针的 next 方法,会从函数的头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式或return语句暂停,也就是执行yield 这一行 // 执行完成会返回一个 Object, // value 就是执行 yield 后面的值,done 表示函数是否执行完毕 g.next() // { value: undefined, done: true } // 因为最后一行 return y 被执行完成,所以done 为 true
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)
。下一步,必须调用遍历器对象的next
方法,使得指针移向下一个状态。
所以上面的回调函数又可以写成这样:
function *fetch() { yield ajax('aaa') yield ajax('bbb') yield ajax('ccc') } let gen = fetch() let res1 = gen.next() // { value: 'aaa', done: false } let res2 = gen.next() // { value: 'bbb', done: false } let res3 = gen.next() // { value: 'ccc', done: false } let res4 = gen.next() // { value: undefined, done: true } done为true表示执行结束
由于 Generator 函数返回的遍历器对象,只有调用next
方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield
表达式就是暂停标志。
遍历器对象的next
方法的运行逻辑如下。
(1)遇到yield
表达式,就暂停执行后面的操作,并将紧跟在yield
后面的那个表达式的值,作为返回的对象的value
属性值。
(2)下一次调用next
方法时,再继续往下执行,直到遇到下一个yield
비동기 솔루션 개발 역사
1. 콜백 기능 Strong>🎜🎜초기 Javascript 코드로 볼 때 ES6가 탄생하기 이전에는 기본적으로 모든 비동기 처리가 콜백 함수를 기반으로 구현되었습니다. 🎜function* foo(x) { var y = 2 * (yield (x + 1)); var z = yield (y / 3); return (x + y + z); } var a = foo(5); a.next() // Object{value:6, done:false} a.next() // Object{value:NaN, done:false} a.next() // Object{value:NaN, done:true} var b = foo(5); b.next() // { value:6, done:false } b.next(12) // { value:8, done:false } b.next(13) // { value:42, done:true }🎜예, ES6에서 나타났습니다. 이전에는 이런 코드가 있었습니다. 코드는 어디에서나 볼 수 있었습니다. 비동기 실행 문제를 해결했지만 우리가 자주 듣는 콜백 지옥 문제가 뒤따릅니다. 🎜
- 순서가 전혀 없습니다. 중첩된 함수 실행이 어렵습니다. 디버깅에 적합하며 유지 관리 및 읽기에 도움이 되지 않습니다.
- 결합이 너무 강합니다. 특정 중첩 수준이 변경되면 전체 콜백 실행에 영향을 미칩니다.
Promise
를 제안하고 구현했으며, ES6에서는 이를 언어 표준으로 작성하여 사용법을 통일했습니다. 🎜🎜2.Promise🎜🎜Promise는 비동기 프로그래밍에 대한 솔루션으로, 기존 솔루션보다 뛰어납니다. 콜백 함수 및 이벤트 - 더욱 합리적이고 강력해졌습니다. 콜백 함수로 인해 발생하는 문제를 해결하기 위해 탄생했습니다. 🎜🎜 Promise
개체를 사용하면 비동기 작업을 동기 작업 프로세스로 표현할 수 있어 중첩된 콜백 함수 레이어를 피할 수 있습니다. 또한 Promise
개체는 통합 인터페이스를 제공하여 비동기 작업을 더 쉽게 제어할 수 있습니다. 🎜🎜그래서 위의 콜백 함수를 다음과 같이 변경할 수 있습니다. (ajax가 Promise로 래핑된 경우)🎜async function fetch() { await ajax('aaa') await ajax('bbb') await ajax('ccc') } // 但这是在这三个请求有相互依赖的前提下可以这么写,不然会产生性能问题,因为你每一个请求都需要等待上一次请求完成后再发起请求,如果没有相互依赖的情况下,建议让它们同时发起请求,这里可以使用Promise.all()来处理🎜
Promise
를 사용하여 비동기식을 처리하면 이전 콜백 함수보다 더 우아해 보입니다. 명확하고 콜백 지옥 문제를 해결합니다. Promise
의 then
체인 호출이 더 수용 가능하며 동기화에 대한 우리의 아이디어와 일치합니다. 🎜🎜그러나 Promise에도 단점이 있습니다. 🎜- Promise의 내부 오류는
try catch
를 사용하여 잡을 수 없으며를 사용한 다음에만 사용할 수 있습니다.
의 두 번째 콜백 또는 캡처를 위한catch
async function fn() { return 'async' } fn().then(res => { console.log(res) // 'async' })
- Promise가 생성되면 즉시 실행되며 취소할 수 없습니다. ul>🎜저는 이전에 Promise 사용 방법과 내부 구현 원칙을 설명하는 기사를 작성했습니다. Promise를 잘 모르는 학생들도 보세요~🎜
🎜Promise 사용법부터 구현 방법까지🎜🎜https://juejin.cn/post/7051364317119119396🎜🎜 3.Generator🎜🎜
Generator
함수는 ES6에서 제공하는 비동기 프로그래밍 솔루션입니다. 구문과 동작은 완전히 동일합니다. 전통적인 기능과 다릅니다. Generator
함수는 JavaScript 비동기 프로그래밍을 완전히 새로운 수준으로 끌어올립니다. 🎜🎜선언🎜🎜은 function
키워드와 함수 이름을 제외하고 함수 선언과 유사합니다. 사이에는 별표가 있으며 yield
표현식은 함수 본문 내에서 다양한 내부 상태를 정의하는 데 사용됩니다(yield
는 영어로 "출력"을 의미함). 🎜function fn() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1000) }, 1000); }) } function fn1() { return 'nanjiu' } async function fn2() { // const value = await fn() // await 右侧表达式为Promise,得到的结果就是Promise成功的value // const value = await '南玖' const value = await fn1() console.log('value', value) } fn2() // value 'nanjiu'🎜실행🎜
console.log('script start') async function async1() { await async2() console.log('async1 end') } async function async2() { console.log('async2 end') } async1() setTimeout(function() { console.log('setTimeout') }, 0) new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') }) console.log('script end')🎜Generator 함수를 호출한 후 함수가 실행되지 않으며 반환되는 것은 함수 연산 결과 내부 상태를 가리키는 포인터 객체, 즉
Iterator 객체
입니다. 다음으로, 반복자 객체의 next
메서드를 호출하여 포인터가 다음 상태로 이동하도록 해야 합니다. 🎜🎜위의 콜백 함수는 다음과 같이 작성할 수 있습니다. 🎜rrreee🎜Generator 함수에서 반환된 순회 개체는 next
메서드를 호출해야만 다음 내부 상태를 순회할 수 있으므로 실제로 다음과 같은 기능을 제공합니다. 실행을 일시 중지하는 함수 방법. yield
표현식은 일시 중지 플래그입니다. 🎜🎜traverser 객체의 next
메소드의 연산 로직은 다음과 같습니다. 🎜🎜(1) yield
표현식이 발생하면 후속 작업의 실행이 일시 중지되고 yield
바로 다음 표현식의 값이 반환된 객체로 사용됩니다. value
속성의 값입니다. 🎜🎜(2) 다음에 next
메서드가 호출되면 다음 yield
표현식이 나타날 때까지 실행이 계속됩니다. 🎜(3)如果没有再遇到新的yield
表达式,就一直运行到函数结束,直到return
语句为止,并将return
语句后面的表达式的值,作为返回的对象的value
属性值。
(4)如果该函数没有return
语句,则返回的对象的value
属性值为undefined
。
yield
表达式本身没有返回值,或者说总是返回undefined
。next
方法可以带一个参数,该参数就会被当作上一个yield
表达式的返回值。
怎么理解这句话?我们来看下面这个例子:
function* foo(x) { var y = 2 * (yield (x + 1)); var z = yield (y / 3); return (x + y + z); } var a = foo(5); a.next() // Object{value:6, done:false} a.next() // Object{value:NaN, done:false} a.next() // Object{value:NaN, done:true} var b = foo(5); b.next() // { value:6, done:false } b.next(12) // { value:8, done:false } b.next(13) // { value:42, done:true }
由于yield
没有返回值,所以(yield(x+1))执行后的值是undefined
,所以在第二次执行a.next()
是其实是执行的2*undefined
,所以值是NaN
,所以下面b的例子中,第二次执行b.next()
时传入了12,它会当成第一次b.next()
的执行返回值,所以b的例子中能够正确计算。这里不能把next执行结果中的value值与yield返回值搞混了,它两不是一个东西
yield与return的区别
相同点:
- 都能返回语句后面的那个表达式的值
- 都可以暂停函数执行
区别:
- 一个函数可以有多个 yield,但是只能有一个 return
- yield 有位置记忆功能,return 没有
4.Async/await
Async/await
其实就是上面Generator
的语法糖,async
函数其实就相当于funciton *
的作用,而await
就相当与yield
的作用。而在async/await
机制中,自动包含了我们上述封装出来的spawn
自动执行函数。
所以上面的回调函数又可以写的更加简洁了:
async function fetch() { await ajax('aaa') await ajax('bbb') await ajax('ccc') } // 但这是在这三个请求有相互依赖的前提下可以这么写,不然会产生性能问题,因为你每一个请求都需要等待上一次请求完成后再发起请求,如果没有相互依赖的情况下,建议让它们同时发起请求,这里可以使用Promise.all()来处理
async
函数对Generator
函数的改进,体现在以下四点:
- 内置执行器:
async
函数执行与普通函数一样,不像Generator
函数,需要调用next
方法,或使用co
模块才能真正执行 - 语意化更清晰:
async
和await
,比起星号和yield
,语义更清楚了。async
表示函数里有异步操作,await
表示紧跟在后面的表达式需要等待结果。 - 适用性更广:
co
模块约定,yield
命令后面只能是 Thunk 函数或 Promise 对象,而async
函数的await
命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。 - 返回值是Promise:
async
函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then
方法指定下一步的操作。
async函数
async函数的返回值为Promise对象,所以它可以调用then方法
async function fn() { return 'async' } fn().then(res => { console.log(res) // 'async' })
await表达式
await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
如果表达式是 promise 对象, await 返回的是 promise 成功的值
如果表达式是其它值, 直接将此值作为 await 的返回值
await后面是Promise对象会阻塞后面的代码,Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果
所以这就是await必须用在async的原因,async刚好返回一个Promise对象,可以异步执行阻塞
function fn() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1000) }, 1000); }) } function fn1() { return 'nanjiu' } async function fn2() { // const value = await fn() // await 右侧表达式为Promise,得到的结果就是Promise成功的value // const value = await '南玖' const value = await fn1() console.log('value', value) } fn2() // value 'nanjiu'
异步方案比较
后三种方案都是为解决传统的回调函数而提出的,所以它们相对于回调函数的优势不言而喻。而async/await
又是Generator
函数的语法糖。
- Promise的内部错误使用
try catch
捕获不到,只能只用then
的第二个回调或catch
来捕获,而async/await
的错误可以用try catch
捕获 -
Promise
一旦新建就会立即执行,不会阻塞后面的代码,而async
函数中await后面是Promise对象会阻塞后面的代码。 -
async
函数会隐式地返回一个promise
,该promise
的reosolve
值就是函数return的值。 - 使用
async
函数可以让代码更加简洁,不需要像Promise
一样需要调用then
方法来获取返回值,不需要写匿名函数处理Promise
的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。
说了这么多,顺便看个题吧~
console.log('script start') async function async1() { await async2() console.log('async1 end') } async function async2() { console.log('async2 end') } async1() setTimeout(function() { console.log('setTimeout') }, 0) new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') }) console.log('script end')
解析:
打印顺序应该是: script start -> async2 end -> Promise -> script end -> async1 end -> promise1 -> promise2 -> setTimeout
老规矩,全局代码自上而下执行,先打印出script start
,然后执行async1(),里面先遇到await async2(),执行async2,打印出async2 end
,然后await后面的代码放入微任务队列,接着往下执行new Promise,打印出Promise
,遇见了resolve,将第一个then方法放入微任务队列,接着往下执行打印出script end
,全局代码执行完了,然后从微任务队列中取出第一个微任务执行,打印出async1 end
,再取出第二个微任务执行,打印出promise1
,然后这个then方法执行完了,当前Promise的状态为fulfilled
,它也可以出发then的回调,所以第二个then这时候又被加进了微任务队列,然后再出微任务队列中取出这个微任务执行,打印出promise2
,此时微任务队列为空,接着执行宏任务队列,打印出setTimeout
。
解题技巧:
- 无论是then还是catch里的回调内容只要代码正常执行或者正常返回,则当前新的Promise实例为fulfilled状态。如果有报错或返回Promise.reject()则新的Promise实例为rejected状态。
- fulfilled状态能够触发then回调
- rejected状态能够触发catch回调
- 执行async函数,返回的是Promise对象
- await相当于Promise的then并且同一作用域下await下面的内容全部作为then中回调的内容
- 异步中先执行微任务,再执行宏任务
【相关推荐:javascript学习教程】
위 내용은 Promise, Generator 및 Async의 차이점에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.


핫 AI 도구

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

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

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

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

인기 기사

뜨거운 도구

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경
