Promise、Generator、Async の違いの簡単な分析
Promise 関数と Async/await 関数は両方とも JavaScript の非同期問題を解決するために使用されますが、両者の違いは何ですか? Promise、Generator、Asyncの違いについては以下の記事で紹介していますので、お役に立てれば幸いです。
Promise
関数と Async/await
関数は、JavaScript の非同期問題を解決するために使用されることを知っています。コールバック関数は非同期を処理し、Promise
は非同期を処理し、Generator
は非同期を処理し、次に Async/await
は非同期を処理します。技術的な更新ごとに JavaScript が非同期を処理する方法になります。現在の観点から見ると、Async/await
は非同期処理の究極のソリューションと考えられており、JS の非同期処理はますます同期タスクに似てきています。 非同期プログラミングの最高の状態は、それが非同期かどうかを心配する必要がないことです。
1. コールバック関数
ES6 の初期の Javascript コードよりajax('aaa', () => { // callback 函数体 ajax('bbb', () => { // callback 函数体 ajax('ccc', () => { // callback 函数体 }) }) })
コールバック地獄 問題が発生します。
- 順序がまったくありません: ネストされた関数の実行デバッグが難しく、メンテナンスや読み取りに役立ちません結合が強すぎます。特定のネスト レベルが変更されると、コールバック全体の実行に影響します
したがって、この問題を解決するために、コミュニティはまず Promise を提案して実装し、ES6 はそれを言語標準に書き込み、その使用方法を統一しました。
2.Promise
Promise は非同期プログラミングのソリューションであり、従来のソリューション コールバック関数やイベントよりも優れています。 - より合理的で強力です。コールバック関数によって引き起こされる問題を解決するために生まれました。
Promise
オブジェクトを使用すると、入れ子になったコールバック関数の層を回避して、非同期操作を同期操作プロセスとして表現できます。さらに、Promise
オブジェクトは統一インターフェイスを提供するため、非同期操作の制御が容易になります。
したがって、上記のコールバック関数を次のように変更できます: (ajax が Promise でラップされている場合)
ajax('aaa').then(res=>{ return ajax('bbb') }).then(res=>{ return ajax('ccc') })
By using Promise
を使用して非同期を処理します。以前のコールバック関数はより明確に見え、コールバック地獄の問題が解決されました。Promise
の then
チェーン コールはより受け入れられ、私たちの同期のアイデアと一致しています。
しかし、Promise には欠点もあります。
- Promise の内部エラーは、
try catch
を使用して捕捉することはできません。使用できるのはtry 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) // 会打印 })
ログイン後にコピー
- または
- catch の 2 番目のコールバックは、作成されるとすぐに実行され、キャンセルすることはできません
私は以前、Promise の使用方法とその内部実装原則を説明する記事を書きました。 Promiseがよく分からない学生はぜひ見てみてください~
Promiseの使い方から実装方法までhttps://juejin.cn/post/7051364317119119396
3.Generator
Generator
関数は、ES6 によって提供される非同期プログラミング ソリューションであり、その構文動作従来の機能とは全く異なります。
Generator
宣言
は関数宣言と似ていますが、
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
ジェネレーター関数を呼び出した後、関数は実行されず、関数の演算結果が返されません。ポインタ 内部状態のポインタ オブジェクト、
Iterator Object (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
の直後の式の値を返します。 オブジェクトの属性値。
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 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

日常生活では、約束と履行の間で問題に遭遇することがよくあります。個人的な関係でもビジネス取引でも、約束を守ることが信頼を築く鍵となります。ただし、コミットメントの是非についてはしばしば議論の余地があります。この記事では、約束の長所と短所を検討し、約束を守る方法についていくつかのアドバイスを提供します。約束されたメリットは明らかです。まず、コミットメントは信頼を築きます。人が約束を守るとき、その人は信頼できる人であると他人に信じ込ませます。信頼は人々の間に確立される絆であり、それは人々をより良くすることができます

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

Promise.resolve() の詳細な説明には、特定のコード例が必要です。Promise は、非同期操作を処理するための JavaScript のメカニズムです。実際の開発では、順番に実行する必要があるいくつかの非同期タスクを処理する必要があることがよくあり、満たされた Promise オブジェクトを返すために Promise.resolve() メソッドが使用されます。 Promise.resolve() は Promise クラスの静的メソッドであり、
