async は es7 です。 async と await は ES7 に新しく追加されたもので、非同期操作のソリューションです。async/await は co モジュールとジェネレーター関數(shù)の糖衣構(gòu)文と言え、より明確なセマンティクスで JS 非同期コードを解決します。名前が示すように、async は「非同期」を意味します。async は関數(shù)が非同期であることを宣言するために使用されます。async と await の間には厳密な規(guī)則があります。両方を互いに分離することはできず、await は async 関數(shù)內(nèi)でのみ記述できます。
このチュートリアルの動(dòng)作環(huán)境: Windows 7 システム、ECMAScript バージョン 6、Dell G3 コンピューター。
ES7 (ES2017) で提案されたフロントエンドの非同期機(jī)能: async、await。
async/await とは
async と await は ES7 の新しいコンテンツです。非同期操作のソリューションとして、async/await は co モジュールと言えます。デバイス機(jī)能の糖衣構(gòu)文の生成。より明確なセマンティクスで js 非同期コードを解決します。
async は、その名前が示すように、「非同期」を意味します。async は、関數(shù)が非同期であることを宣言するために使用されます。また、await は文字通り「待機(jī)」を意味し、非同期の完了を待つために使用されます。
Async と await には厳密な規(guī)則があり、両者を分離することはできませんが、await は async 関數(shù)內(nèi)でのみ記述できます。
co モジュールに精通している學(xué)生は、co モジュールがマスター TJ によって書かれたモジュールであり、ジェネレーター関數(shù)を使用して非同期プロセスを解決するモジュールであることを知っているはずです。関數(shù)。 Async/await は co モジュールのアップグレードであり、ジェネレーター関數(shù)エグゼキューターが組み込まれており、co モジュールに依存しなくなりました。同時(shí)に、async は Promise を返します。
上記の観點(diǎn)から、co モジュールにしろ async/await にしろ、Promise は最も基本的な単元として使用されるため、Promise についてあまり知らない學(xué)生は、まず Promise について詳しく學(xué)ぶことができます。
Promise、co、async/awaitの比較
簡(jiǎn)単な例を使用して、3 つの方法の類似點(diǎn)、相違點(diǎn)、トレードオフを比較してみましょう。
例として、mongodb の nodejs ドライバーを使用して mongodb データベースをクエリします。その理由は、mongodb の js ドライバーがデフォルトで Promise を返すように実裝されており、Promise を個(gè)別にラップする必要がないためです。
Promise チェーンを使用する
MongoClient.connect(url + db_name).then(db => { return db.collection('blogs'); }).then(coll => { return coll.find().toArray(); }).then(blogs => { console.log(blogs.length); }).catch(err => { console.log(err); })
Promise の then() メソッドは、別の Promise または同期された値を返すことができます。同期された値が返された場(chǎng)合は、約束。上記の例では、 db.collection() は同期された値、つまりコレクション オブジェクトを返しますが、それは Promise にラップされ、次の then() メソッドに透過的に渡されます。上の例では Promise チェーンを使用しています。まずデータベースに接続します MongoClient.connect() は Promise を返し、次に then() メソッドでデータベース オブジェクト db を取得し、次に coll オブジェクトを取得して返します。次の then() メソッドで coll オブジェクトを取得し、クエリを?qū)g行してクエリ結(jié)果を返し、then() メソッドをレイヤーごとに呼び出して Promise チェーンを形成します。この Promise チェーンでは、いずれかのリンクで例外が発生すると、最後の catch() によってキャッチされます。 Promise チェーンを使用して記述されたこのコードは、レイヤーごとにコールバック関數(shù)を呼び出すよりも洗練されており、プロセスが明確であると言えます。最初にデータベース オブジェクトを取得し、次にコレクション オブジェクトを取得し、最後にデータをクエリします。しかし、ここにはあまり「エレガント」ではない問題があります。それは、各 then() メソッドによって取得されたオブジェクトが、前の then() メソッドによって返されたデータであるということです。レイヤーを越えてアクセスすることはできません。これはどういう意味ですか。つまり、3 番目の then (blogs => {}) では、クエリ結(jié)果 blogs のみを取得できますが、上記の db オブジェクトと coll オブジェクトは使用できません。このとき、ブログ一覧を出力した後にデータベース db.close() を閉じたい場(chǎng)合はどうすればよいでしょうか?,F(xiàn)時(shí)點(diǎn)では、解決策が 2 つあります。
1 つ目は、then() ネストを使用することです。コールバック関數(shù)のネストを使用するのと同じように、Promise チェーンを分割してネストさせます。
MongoClient.connect(url + db_name).then(db => { let coll = db.collection('blogs'); coll.find().toArray().then(blogs => { console.log(blogs.length); db.close(); }).catch(err => { console.log(err); }); }).catch(err => { console.log(err); })
ここでは 2 つの Promise をネストして、最後のクエリ操作で外部の db オブジェクトを呼び出すことができるようにします。ただし、この方法はお?jiǎng)幛幛扦蓼护蟆@碛嗓虾?jiǎn)単です。ある種類のコールバック関數(shù)地獄から別の種類の Promise コールバック地獄に変わったからです。
さらに、Promise はチェーンを形成しないため、各 Promise の例外をキャッチする必要があります。
もう 1 つの方法は、各 then() メソッドで db を渡すことです:
MongoClient.connect(url + db_name).then(db => { return {db:db,coll:db.collection('blogs')}; }).then(result => { return {db:result.db,blogs:result.coll.find().toArray()}; }).then(result => { return result.blogs.then(blogs => { //注意這里,result.coll.find().toArray()返回的是一個(gè)Promise,因此這里需要再解析一層 return {db:result.db,blogs:blogs} }) }).then(result => { console.log(result.blogs.length); result.db.close(); }).catch(err => { console.log(err); });
各 then() メソッドの戻りでは、他の結(jié)果が形成されるたびに db とその DB を渡します。オブジェクトが返されました。各結(jié)果が同期された値である場(chǎng)合は問題ありませんが、それが Promise 値である場(chǎng)合、各 Promise には追加の解析層が必要になることに注意してください。
たとえば、上記の例では、2 番目の then() メソッドによって返される {db:result.db,blogs:result.coll.find().toArray()}
オブジェクト內(nèi)で、 blogs
は Promise です。次の then() メソッドでは、ブログ リストの配列値を直接參照できないため、then() メソッドを呼び出して最初に 1 つのレイヤーを解析し、次に 2 つのレイヤーを返す必要があります。値データベースとブログを同期します。これには Promise のネストが含まれますが、Promise は then() の 1 レベルのみをネストすることに注意してください。
這種方式,也是很蛋疼的一個(gè)方式,因?yàn)槿绻龅絫hen()方法中返回的不是同步的值,而是Promise的話,我們需要多做很多工作。而且,每次都透?jìng)饕粋€(gè)“多余”的db對(duì)象,在邏輯上也有點(diǎn)冗余。
但除此之外,對(duì)于Promise鏈的使用,如果遇到上面的問題,好像也沒其他更好的方法解決了。我們只能根據(jù)場(chǎng)景去選擇一種“最優(yōu)”的方案,如果要使用Promise鏈的話。
鑒于Promise上面蛋疼的問題,TJ大神將ES6中的生成器函數(shù),用co模塊包裝了一下,以更優(yōu)雅的方式來解決上面的問題。
co搭配生成器函數(shù)
如果使用co模塊搭配生成器函數(shù),那么上面的例子可以改寫如下:
const co = require('co'); co(function* (){ let db = yield MongoClient.connect(url + db_name); let coll = db.collection('blogs'); let blogs = yield coll.find().toArray(); console.log(blogs.length); db.close(); }).catch(err => { console.log(err); });
co是一個(gè)函數(shù),將接受一個(gè)生成器函數(shù)作為參數(shù),去執(zhí)行這個(gè)生成器函數(shù)。生成器函數(shù)中使用yield
關(guān)鍵字來“同步”獲取每個(gè)異步操作的值。
上面代碼在代碼形式上,比上面使用Promise鏈要優(yōu)雅,我們消滅了回調(diào)函數(shù),代碼看起來都是同步的。除了使用co和yield有點(diǎn)怪之外。
使用co模塊,我們要將所有的操作包裝成一個(gè)生成器函數(shù),然后使用co()去調(diào)用這個(gè)生成器函數(shù)??瓷先ヒ策€可以接受,但是ES的進(jìn)化是不滿足于此的,于是async/await被提到了ES7的提案。
async/await
我們先看一下使用async/await改寫上面的代碼:
(async function(){ let db = await MongoClient.connect(url + db_name); let coll = db.collection('blogs'); let blogs = await coll.find().toArray(); console.log(blogs.length); db.close(); })().catch(err => { console.log(err); });
我們對(duì)比代碼可以看出,async/await和co兩種方式代碼極為相似。co換成了async,yield換成了await。同時(shí)生成器函數(shù)變成了普通函數(shù)。這種方式在語(yǔ)義上更加清晰明了,async表明這個(gè)函數(shù)是異步的,同時(shí)await表示要“等待”異步操作返回值。
async函數(shù)返回一個(gè)Promise,上面的代碼其實(shí)是這樣:
let getBlogs = async function(){ let db = await MongoClient.connect(url + db_name); let coll = db.collection('blogs'); let blogs = await coll.find().toArray(); db.close(); return blogs; }; getBlogs().then(result => { console.log(result.length); }).catch(err => { console.log(err); })
我們定義getBlogs為一個(gè)async函數(shù),最后返回得到的博客列表最終會(huì)被包裝成一個(gè)Promise返回,如上,我們直接調(diào)用getBlogs().then()方法可獲取async函數(shù)返回值。
好了,上面我們簡(jiǎn)單對(duì)比了一下三種解決異步方案,下面我們來深入了解一下async/await。
深入async/await
async返回值
async用于定義一個(gè)異步函數(shù),該函數(shù)返回一個(gè)Promise。
如果async函數(shù)返回的是一個(gè)同步的值,這個(gè)值將被包裝成一個(gè)理解resolve的Promise,等同于return Promise.resolve(value)
。
await用于一個(gè)異步操作之前,表示要“等待”這個(gè)異步操作的返回值。await也可以用于一個(gè)同步的值。
//返回一個(gè)Promise let timer = async function timer(){ return new Promise((resolve,reject) => { setTimeout(() => { resolve('500'); },500); }); } timer().then(result => { console.log(result); //500 }).catch(err => { console.log(err.message); });
//返回一個(gè)同步的值 let sayHi = async function sayHi(){ let hi = await 'hello world'; return hi; //等同于return Promise.resolve(hi); } sayHi().then(result => { console.log(result); });
上面這個(gè)例子返回是一個(gè)同步的值,字符串’hello world’,sayHi()是一個(gè)async函數(shù),返回值被包裝成一個(gè)Promise,可以調(diào)用then()方法獲取返回值。對(duì)于一個(gè)同步的值,可以使用await,也可以不使用await。效果效果是一樣的。具體用不用,看情況。
比如上面使用mongodb查詢博客那個(gè)例子,let coll = db.collection('blogs');
,這里我們就沒有用await,因?yàn)檫@是一個(gè)同步的值。當(dāng)然,也可以使用await,這樣會(huì)顯得代碼統(tǒng)一。雖然效果是一樣的。
async函數(shù)的異常
let sayHi = async function sayHi(){ throw new Error('出錯(cuò)了'); } sayHi().then(result => { console.log(result); }).catch(err => { console.log(err.message); //出錯(cuò)了 });
我們直接在async函數(shù)中拋出一個(gè)異常,由于返回的是一個(gè)Promise,因此,這個(gè)異常可以調(diào)用返回Promise的catch()方法捕捉到。
和Promise鏈的對(duì)比:
我們的async函數(shù)中可以包含多個(gè)異步操作,其異常和Promise鏈有相同之處,如果有一個(gè)Promise被reject()那么后面的將不會(huì)再進(jìn)行。
let count = ()=>{ return new Promise((resolve,reject) => { setTimeout(()=>{ reject('故意拋出錯(cuò)誤'); },500); }); } let list = ()=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve([1,2,3]); },500); }); } let getList = async ()=>{ let c = await count(); let l = await list(); return {count:c,list:l}; } console.time('begin'); getList().then(result => { console.log(result); }).catch(err => { console.timeEnd('begin'); console.log(err); }); //begin: 507.490ms //故意拋出錯(cuò)誤
如上面的代碼,定義兩個(gè)異步操作,count和list,使用setTimeout延時(shí)500毫秒,count故意直接拋出異常,從輸出結(jié)果來看,count()拋出異常后,直接由catch()捕捉到了,list()并沒有繼續(xù)執(zhí)行。
并行
使用async后,我們上面的例子都是串行的。比如上個(gè)list()和count()的例子,我們可以將這個(gè)例子用作分頁(yè)查詢數(shù)據(jù)的場(chǎng)景。先查詢出數(shù)據(jù)庫(kù)中總共有多少條記錄,然后再根據(jù)分頁(yè)條件查詢分頁(yè)數(shù)據(jù),最后返回分頁(yè)數(shù)據(jù)以及分頁(yè)信息。
我們上面的例子count()和list()有個(gè)“先后順序”,即我們先查的總數(shù),然后又查的列表。其實(shí),這兩個(gè)操作并無(wú)先后關(guān)聯(lián)性,我們可以異步的同時(shí)進(jìn)行查詢,然后等到所有結(jié)果都返回時(shí)再拼裝數(shù)據(jù)即可。
let count = ()=>{ return new Promise((resolve,reject) => { setTimeout(()=>{ resolve(100); },500); }); } let list = ()=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve([1,2,3]); },500); }); } let getList = async ()=>{ let result = await Promise.all([count(),list()]); return result; } console.time('begin'); getList().then(result => { console.timeEnd('begin'); //begin: 505.557ms console.log(result); //[ 100, [ 1, 2, 3 ] ] }).catch(err => { console.timeEnd('begin'); console.log(err); });
我們將count()和list()使用Promise.all()“同時(shí)”執(zhí)行,這里count()和list()可以看作是“并行”執(zhí)行的,所耗時(shí)間將是兩個(gè)異步操作中耗時(shí)最長(zhǎng)的耗時(shí)。
最終結(jié)果は、2 つの操作の結(jié)果で構(gòu)成される配列です。配列內(nèi)の値を順番に取り出すだけです。
[推奨學(xué)習(xí): JavaScript ビデオ チュートリアル ]
以上が非同期は es6 または es7 用ですか?の詳細(xì)內(nèi)容です。詳細(xì)については、PHP 中國(guó)語(yǔ) Web サイトの他の関連記事を參照してください。

ホットAIツール

Undress AI Tool
脫衣畫像を無(wú)料で

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

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

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無(wú)料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡(jiǎn)単に交換できます。

人気の記事

ホットツール

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

SublimeText3 中國(guó)語(yǔ)版
中國(guó)語(yǔ)版、とても使いやすい

ゼンドスタジオ 13.0.1
強(qiáng)力な PHP 統(tǒng)合開発環(huán)境

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

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

ホットトピック

ES6 では、配列オブジェクトの reverse() メソッドを使用して、配列の反転を?qū)g現(xiàn)できます。このメソッドは、配列內(nèi)の要素の順序を逆にして、最後の要素を最初に、最初の要素を最後に配置するために使用されます。構(gòu)文「array」 。逆行する()"。 reverse() メソッドは元の配列を変更します。変更したくない場(chǎng)合は、拡張演算子 "..." とともに使用する必要があり、構(gòu)文は "[...array].reverse() 」。

非同期はes7です。 async と await は ES7 に新しく追加されたもので、非同期操作のソリューションです。async/await は co モジュールとジェネレーター関數(shù)の糖衣構(gòu)文と言え、より明確なセマンティクスで JS 非同期コードを解決します。名前が示すように、async は「非同期」を意味します。async は関數(shù)が非同期であることを宣言するために使用されます。async と await の間には厳密な規(guī)則があります。両方を互いに分離することはできず、await は async 関數(shù)內(nèi)でのみ記述できます。

ブラウザの互換性のため。 ES6 は JS の新しい仕様として、多くの新しい構(gòu)文と API を追加していますが、最新のブラウザーは ES6 の新機(jī)能を高度にサポートしていないため、ES6 コードを ES5 コードに変換する必要があります。 WeChat Web 開発者ツールでは、デフォルトで babel が使用され、開発者の ES6 構(gòu)文コードを 3 つの端末すべてで適切にサポートされる ES5 コードに変換し、開発者がさまざまな環(huán)境によって引き起こされる開発上の問題を解決できるようにします。プロジェクト內(nèi)でのみ設(shè)定して確認(rèn)するだけです。 「ES6~ES5」オプション。

手順: 1. 構(gòu)文 "newA=new Set(a); newB=new Set(b);" を使用して、2 つの配列をそれぞれセット型に変換します; 2. has() と filter() を使用して差分セットを検索します、構(gòu)文 " new Set([...newA].filter(x =>!newB.has(x)))" では、差分セット要素がセット コレクションに含まれて返されます。 3. 配列を使用します。 from セットを配列に変換するタイプ、構(gòu)文は「Array.from(collection)」です。

es5 では、for ステートメントと IndexOf() 関數(shù)を使用して配列の重複排除を?qū)g現(xiàn)できます。構(gòu)文 "for(i=0;i<配列長(zhǎng);i++){a=newArr.indexOf(arr[i]);if( a== -1){...}}」。 es6 では、スプレッド演算子 Array.from() および Set を使用して重複を削除できます。まず配列を Set オブジェクトに変換して重複を削除してから、スプレッド演算子または Array.from() 関數(shù)を使用する必要があります。 Set オブジェクトを配列に変換してグループ化するだけです。

es6 では、一時(shí)的なデッド ゾーンは構(gòu)文エラーであり、ブロックを閉じたスコープにする let および const コマンドを指します。コード ブロック內(nèi)では、let/const コマンドを使用して変數(shù)が宣言される前に、変數(shù)は使用できず、変數(shù)が宣言される前は変數(shù)の「デッド ゾーン」に屬します。これは構(gòu)文上「一時(shí)デッド ゾーン」と呼ばれます。 ES6 では、一時(shí)的なデッド ゾーンや let ステートメントや const ステートメントでは変數(shù)のプロモーションが発生しないことを規(guī)定しています。これは主に実行時(shí)エラーを減らし、変數(shù)が宣言される前に使用されて予期しない動(dòng)作が発生するのを防ぐためです。

ES6 では、配列オブジェクトの length 屬性を使用して、配列內(nèi)にある項(xiàng)目の數(shù)を決定する、つまり、配列內(nèi)の要素の數(shù)を取得できます。この屬性は、配列內(nèi)の要素の數(shù)を返すことができます。 "array.length" ステートメントを使用すると、配列オブジェクトの要素の數(shù)を表す値、つまり長(zhǎng)さの値が返されます。

ES6 インポートにより変數(shù)が昇格されます。変數(shù)ホイスティングとは、変數(shù)宣言をそのスコープの先頭に昇格させることです。 js はコンパイルと実行のフェーズを経る必要があります。コンパイル フェーズでは、すべての変數(shù)宣言が収集され、変數(shù)は事前に宣言され、他のステートメントの順序は変更されません。したがって、コンパイル フェーズでは、最初のステップはすでに2 番目の部分は、ステートメントが実行フェーズで実行された場(chǎng)合にのみ実行されます。
