目次
async/await とは
Promise、co、async/awaitの比較
Promise チェーンを使用する
co搭配生成器函数
async/await
深入async/await
async返回值
async函数的异常
并行
ホームページ ウェブフロントエンド フロントエンドQ&A 非同期は es6 または es7 用ですか?

非同期は es6 または es7 用ですか?

Jan 29, 2023 pm 05:36 PM
es6 async await es7 async

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

非同期は es6 または es7 用ですか?

このチュートリアルの動作環境: Windows 7 システム、ECMAScript バージョン 6、Dell G3 コンピューター。

ES7 (ES2017) で提案されたフロントエンドの非同期機能: async、await。

async/await とは

async と await は ES7 の新しいコンテンツです。非同期操作のソリューションとして、async/await は co モジュールと言えます。デバイス機能の糖衣構文の生成。より明確なセマンティクスで js 非同期コードを解決します。

async は、その名前が示すように、「非同期」を意味します。async は、関数が非同期であることを宣言するために使用されます。また、await は文字通り「待機」を意味し、非同期の完了を待つために使用されます。

Async と await には厳密な規則があり、両者を分離することはできませんが、await は async 関数内でのみ記述できます。

co モジュールに精通している学生は、co モジュールがマスター TJ によって書かれたモジュールであり、ジェネレーター関数を使用して非同期プロセスを解決するモジュールであることを知っているはずです。関数。 Async/await は co モジュールのアップグレードであり、ジェネレーター関数エグゼキューターが組み込まれており、co モジュールに依存しなくなりました。同時に、async は Promise を返します。

上記の観点から、co モジュールにしろ async/await にしろ、Promise は最も基本的な単元として使用されるため、Promise についてあまり知らない学生は、まず Promise について詳しく学ぶことができます。

Promise、co、async/awaitの比較

簡単な例を使用して、3 つの方法の類似点、相違点、トレードオフを比較してみましょう。

例として、mongodb の nodejs ドライバーを使用して mongodb データベースをクエリします。その理由は、mongodb の js ドライバーがデフォルトで Promise を返すように実装されており、Promise を個別にラップする必要がないためです。

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 または同期された値を返すことができます。同期された値が返された場合は、約束。上記の例では、 db.collection() は同期された値、つまりコレクション オブジェクトを返しますが、それは Promise にラップされ、次の then() メソッドに透過的に渡されます。上の例では Promise チェーンを使用しています。まずデータベースに接続します MongoClient.connect() は Promise を返し、次に then() メソッドでデータベース オブジェクト db を取得し、次に coll オブジェクトを取得して返します。次の then() メソッドで coll オブジェクトを取得し、クエリを実行してクエリ結果を返し、then() メソッドをレイヤーごとに呼び出して Promise チェーンを形成します。この Promise チェーンでは、いずれかのリンクで例外が発生すると、最後の catch() によってキャッチされます。 Promise チェーンを使用して記述されたこのコードは、レイヤーごとにコールバック関数を呼び出すよりも洗練されており、プロセスが明確であると言えます。最初にデータベース オブジェクトを取得し、次にコレクション オブジェクトを取得し、最後にデータをクエリします。しかし、ここにはあまり「エレガント」ではない問題があります。それは、各 then() メソッドによって取得されたオブジェクトが、前の then() メソッドによって返されたデータであるということです。レイヤーを越えてアクセスすることはできません。これはどういう意味ですか。つまり、3 番目の then (blogs => {}) では、クエリ結果 blogs のみを取得できますが、上記の db オブジェクトと coll オブジェクトは使用できません。このとき、ブログ一覧を出力した後にデータベース db.close() を閉じたい場合はどうすればよいでしょうか。現時点では、解決策が 2 つあります。

1 つ目は、then() ネストを使用することです。コールバック関数のネストを使用するのと同じように、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 オブジェクトを呼び出すことができるようにします。ただし、この方法はお勧めできません。理由は簡単です。ある種類のコールバック関数地獄から別の種類の 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()返回的是一个Promise,因此这里需要再解析一层
        return {db:result.db,blogs:blogs}
    })
}).then(result => {
    console.log(result.blogs.length);
    result.db.close();
}).catch(err => {
    console.log(err);
});
ログイン後にコピー

各 then() メソッドの戻りでは、他の結果が形成されるたびに db とその DB を渡します。オブジェクトが返されました。各結果が同期された値である場合は問題ありませんが、それが Promise 値である場合、各 Promise には追加の解析層が必要になることに注意してください。
たとえば、上記の例では、2 番目の then() メソッドによって返される {db:result.db,blogs:result.coll.find().toArray()} オブジェクト内で、 blogs は Promise です。次の then() メソッドでは、ブログ リストの配列値を直接参照できないため、then() メソッドを呼び出して最初に 1 つのレイヤーを解析し、次に 2 つのレイヤーを返す必要があります。値データベースとブログを同期します。これには Promise のネストが含まれますが、Promise は then() の 1 レベルのみをネストすることに注意してください。

这种方式,也是很蛋疼的一个方式,因为如果遇到then()方法中返回的不是同步的值,而是Promise的话,我们需要多做很多工作。而且,每次都透传一个“多余”的db对象,在逻辑上也有点冗余。

但除此之外,对于Promise链的使用,如果遇到上面的问题,好像也没其他更好的方法解决了。我们只能根据场景去选择一种“最优”的方案,如果要使用Promise链的话。

鉴于Promise上面蛋疼的问题,TJ大神将ES6中的生成器函数,用co模块包装了一下,以更优雅的方式来解决上面的问题。

co搭配生成器函数

如果使用co模块搭配生成器函数,那么上面的例子可以改写如下:

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是一个函数,将接受一个生成器函数作为参数,去执行这个生成器函数。生成器函数中使用yield关键字来“同步”获取每个异步操作的值。
上面代码在代码形式上,比上面使用Promise链要优雅,我们消灭了回调函数,代码看起来都是同步的。除了使用co和yield有点怪之外。

使用co模块,我们要将所有的操作包装成一个生成器函数,然后使用co()去调用这个生成器函数。看上去也还可以接受,但是ES的进化是不满足于此的,于是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);
});
ログイン後にコピー

我们对比代码可以看出,async/await和co两种方式代码极为相似。co换成了async,yield换成了await。同时生成器函数变成了普通函数。这种方式在语义上更加清晰明了,async表明这个函数是异步的,同时await表示要“等待”异步操作返回值。

async函数返回一个Promise,上面的代码其实是这样:

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为一个async函数,最后返回得到的博客列表最终会被包装成一个Promise返回,如上,我们直接调用getBlogs().then()方法可获取async函数返回值。

好了,上面我们简单对比了一下三种解决异步方案,下面我们来深入了解一下async/await。

深入async/await

async返回值

async用于定义一个异步函数,该函数返回一个Promise。
如果async函数返回的是一个同步的值,这个值将被包装成一个理解resolve的Promise,等同于return Promise.resolve(value)
await用于一个异步操作之前,表示要“等待”这个异步操作的返回值。await也可以用于一个同步的值。

//返回一个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);
});
ログイン後にコピー
//返回一个同步的值
let sayHi = async function sayHi(){
  let hi = await 'hello world';   
  return hi;  //等同于return Promise.resolve(hi);
}
sayHi().then(result => {
  console.log(result);
});
ログイン後にコピー

上面这个例子返回是一个同步的值,字符串’hello world’,sayHi()是一个async函数,返回值被包装成一个Promise,可以调用then()方法获取返回值。对于一个同步的值,可以使用await,也可以不使用await。效果效果是一样的。具体用不用,看情况。

比如上面使用mongodb查询博客那个例子,let coll = db.collection('blogs');,这里我们就没有用await,因为这是一个同步的值。当然,也可以使用await,这样会显得代码统一。虽然效果是一样的。

async函数的异常

let sayHi = async function sayHi(){
    throw new Error('出错了');
}
sayHi().then(result => {
  console.log(result);
}).catch(err => {
    console.log(err.message);   //出错了
});
ログイン後にコピー

我们直接在async函数中抛出一个异常,由于返回的是一个Promise,因此,这个异常可以调用返回Promise的catch()方法捕捉到。

和Promise链的对比:
我们的async函数中可以包含多个异步操作,其异常和Promise链有相同之处,如果有一个Promise被reject()那么后面的将不会再进行。

let count = ()=>{
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            reject('故意抛出错误');
        },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
//故意抛出错误
ログイン後にコピー

如上面的代码,定义两个异步操作,count和list,使用setTimeout延时500毫秒,count故意直接抛出异常,从输出结果来看,count()抛出异常后,直接由catch()捕捉到了,list()并没有继续执行。

并行

使用async后,我们上面的例子都是串行的。比如上个list()和count()的例子,我们可以将这个例子用作分页查询数据的场景。先查询出数据库中总共有多少条记录,然后再根据分页条件查询分页数据,最后返回分页数据以及分页信息。

我们上面的例子count()和list()有个“先后顺序”,即我们先查的总数,然后又查的列表。其实,这两个操作并无先后关联性,我们可以异步的同时进行查询,然后等到所有结果都返回时再拼装数据即可。

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()“同时”执行,这里count()和list()可以看作是“并行”执行的,所耗时间将是两个异步操作中耗时最长的耗时。

最終結果は、2 つの操作の結果で構成される配列です。配列内の値を順番に取り出すだけです。

[推奨学習: JavaScript ビデオ チュートリアル ]

以上が非同期は es6 または es7 用ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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ヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

ES6 で配列を反転する方法 ES6 で配列を反転する方法 Oct 26, 2022 pm 06:19 PM

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

非同期は es6 または es7 用ですか? 非同期は es6 または es7 用ですか? Jan 29, 2023 pm 05:36 PM

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

es6 の 2 つの配列で異なる項目を見つける方法 es6 の 2 つの配列で異なる項目を見つける方法 Nov 01, 2022 pm 06:07 PM

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

ミニ プログラムで es6 を es5 に変換する必要があるのはなぜですか? ミニ プログラムで es6 を es5 に変換する必要があるのはなぜですか? Nov 21, 2022 pm 06:15 PM

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

es5 および es6 で配列重複排除を実装する方法 es5 および es6 で配列重複排除を実装する方法 Jan 16, 2023 pm 05:09 PM

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

es6 の一時的なデッドゾーンとは何を意味しますか? es6 の一時的なデッドゾーンとは何を意味しますか? Jan 03, 2023 pm 03:56 PM

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

es6 構文が必要ですか? es6 構文が必要ですか? Oct 21, 2022 pm 04:09 PM

いいえ、require は CommonJS 仕様のモジュール構文であり、es6 仕様のモジュール構文は import です。 require は実行時にロードされ、import はコンパイル時にロードされます。require はコード内のどこにでも記述できます。import はファイルの先頭にのみ記述でき、条件文や関数スコープでは使用できません。モジュール属性は導入されるだけです。 require を実行した場合、そのためパフォーマンスは比較的低くなりますが、インポート コンパイル中に導入されたモジュールのプロパティのパフォーマンスはわずかに高くなります。

es6 マップは注文されていますか? es6 マップは注文されていますか? Nov 03, 2022 pm 07:05 PM

地図は注文済みです。 ES6 のマップ タイプは、多くのキーと値のペアを格納する順序付きリストです。キー名と対応する値はすべてのデータ型をサポートします。キー名の等価性は、「Objext.is()」メソッドを呼び出すことによって決定されます。 , したがって、数字の 5 と文字列「5」は 2 つのタイプとして判断され、プログラム内で 2 つの独立したキーとして現れることができます。

See all articles