この記事では、ES6 でのジェネレーターの自動実行について詳しく説明します。必要な方は参考にしていただければ幸いです。
単一の非同期タスク
var fetch = require('node-fetch'); function* gen(){ var url = 'https://api.github.com/users/github'; var result = yield fetch(url); console.log(result.bio); }
最終的な実行結果を取得するには、これを行う必要があります:
var g = gen(); var result = g.next(); result.value.then(function(data){ return data.json(); }).then(function(data){ g.next(data); });
最初にジェネレーター関数を実行し、トラバーサー オブジェクトを取得します。
次に、次のメソッドを使用して、非同期タスクの最初のフェーズである fetch(url) を実行します。
fetch(url) は Promise オブジェクトを返すため、result の値は次のようになります:
{ value: Promise { <pending> }, done: false }</pending>
最後に、この Promise オブジェクトに then メソッドを追加し、最初に返されるデータをフォーマットします。 . (data.json()) を呼び出し、取得したデータを渡すために g.next を呼び出します。これにより、非同期タスクの 2 番目のフェーズが実行され、コードの実行が完了します。
複数の非同期タスク
前のセクションでは 1 つのインターフェイスだけを呼び出したので、複数のインターフェイスを呼び出して複数の yield を使用した場合、継続的にネストする必要があるのではないでしょうか。 then 関数内...
それでは、複数の非同期タスクの実行を見てみましょう:
var fetch = require('node-fetch'); function* gen() { var r1 = yield fetch('https://api.github.com/users/github'); var r2 = yield fetch('https://api.github.com/users/github/followers'); var r3 = yield fetch('https://api.github.com/users/github/repos'); console.log([r1.bio, r2[0].login, r3[0].full_name].join('\n')); }
最終的な実行結果を取得するには、次のように記述する必要がある場合があります:
var g = gen(); var result1 = g.next(); result1.value.then(function(data){ return data.json(); }) .then(function(data){ return g.next(data).value; }) .then(function(data){ return data.json(); }) .then(function(data){ return g.next(data).value }) .then(function(data){ return data.json(); }) .then(function(data){ g.next(data) });
しかし、このように書きたくないのはわかっています...
実際、再帰を使用すると、次のように書くことができます:
function run(gen) { var g = gen(); function next(data) { var result = g.next(data); if (result.done) return; result.value.then(function(data) { return data.json(); }).then(function(data) { next(data); }); } next(); } run(gen);
重要なのはyield 時に Promise オブジェクトを返すには、この Promise オブジェクトに then メソッドを追加し、非同期操作が成功したときに実行します。 次に、onFullfilled 関数が onFullfilled 関数内で g.next を実行するため、ジェネレーターは次のことを行うことができます。 実行を継続し、Promise を返し、成功したら g.next を実行して戻ります...
スターター関数
このスターター関数を実行し、データをフォーマットしますthen 関数 data.json() 内ですが、より一般的な場合、たとえば、fetch 関数によって返される Promise ではなく、yield の後に Promise が直接続きます。json メソッドがないため、コードはエラーを報告します。 。したがって、より汎用性を高めるために、この例とスターターを合わせて、次のように変更しました。
var fetch = require('node-fetch'); function* gen() { var r1 = yield fetch('https://api.github.com/users/github'); var json1 = yield r1.json(); var r2 = yield fetch('https://api.github.com/users/github/followers'); var json2 = yield r2.json(); var r3 = yield fetch('https://api.github.com/users/github/repos'); var json3 = yield r3.json(); console.log([json1.bio, json2[0].login, json3[0].full_name].join('\n')); } function run(gen) { var g = gen(); function next(data) { var result = g.next(data); if (result.done) return; result.value.then(function(data) { next(data); }); } next(); } run(gen);
yield の後に Promise オブジェクトが続く限り、この run 関数を使用して Generator 関数を自動的に実行できます。 。
コールバック関数
ジェネレーターを確実に自動実行するには、yield の後に Promise オブジェクトを続ける必要がありますか?それが単なるコールバック関数の場合はどうなるでしょうか?例を見てみましょう:
まず、通常の非同期リクエストをシミュレートします:
function fetchData(url, cb) { setTimeout(function(){ cb({status: 200, data: url}) }, 1000) }
この関数を次のように変換します:
function fetchData(url) { return function(cb){ setTimeout(function(){ cb({status: 200, data: url}) }, 1000) } }
そのようなジェネレーター関数の場合:
function* gen() { var r1 = yield fetchData('https://api.github.com/users/github'); var r2 = yield fetchData('https://api.github.com/users/github/followers'); console.log([r1.data, r2.data].join('\n')); }
最終結果を取得したい場合:
var g = gen(); var r1 = g.next(); r1.value(function(data) { var r2 = g.next(data); r2.value(function(data) { g.next(data); }); });
このように書くと、最初のセクションと同じ問題に直面します。つまり、複数の yield を使用する場合、コードは次のように埋め込まれます。ループ それをまとめると...
も再帰を使用するので、次のように変換できます:
function run(gen) { var g = gen(); function next(data) { var result = g.next(data); if (result.done) return; result.value(next); } next(); } run(gen);
run
これからわかるようにジェネレーター機能 自動実行には、非同期操作の結果が得られたときに実行権限を自動的に引き渡すことができるメカニズムが必要です。
そして、これを行うには 2 つの方法があります。
(1) コールバック関数。非同期操作をラップし、コールバック関数を公開し、コールバック関数の実行権限を返します。
(2) Promise オブジェクト。非同期操作を Promise オブジェクトにラップし、 then メソッドを使用して実行権限を返します。
2 つのメソッドのそれぞれで、実行ランチャー関数を作成しました。これら 2 つのメソッドを組み合わせて、一般的な実行関数を作成できますか?試してみましょう:
// 第一版 function run(gen) { var gen = gen(); function next(data) { var result = gen.next(data); if (result.done) return; if (isPromise(result.value)) { result.value.then(function(data) { next(data); }); } else { result.value(next) } } next() } function isPromise(obj) { return 'function' == typeof obj.then; } module.exports = run;
実際、実装は非常に簡単です。result.value が Promise であるかどうかを判断し、そうでない場合は then 関数を追加します。
return Promise
yield に続いてコールバック関数または Promise オブジェクトをサポートする優れたスターター関数を作成しました。
ここで考えるべき問題があります。それは、ジェネレーター関数の戻り値をどのように取得するかということです。また、存在しないインターフェイスをフェッチするなど、ジェネレーター関数でエラーが発生した場合、このエラーをどのようにキャッチすればよいでしょうか?
これは簡単に考えられます Promise、このスターター関数が Promise を返す場合、この Promise オブジェクトに then を追加できます。 関数では、すべての非同期操作が正常に実行された場合は onFullfilled 関数を実行し、失敗した場合は onRejected 関数を実行します。
バージョンを作成します:
// 第二版 function run(gen) { var gen = gen(); return new Promise(function(resolve, reject) { function next(data) { try { var result = gen.next(data); } catch (e) { return reject(e); } if (result.done) { return resolve(result.value) }; var value = toPromise(result.value); value.then(function(data) { next(data); }, function(e) { reject(e) }); } next() }) } function isPromise(obj) { return 'function' == typeof obj.then; } function toPromise(obj) { if (isPromise(obj)) return obj; if ('function' == typeof obj) return thunkToPromise(obj); return obj; } function thunkToPromise(fn) { return new Promise(function(resolve, reject) { fn(function(err, res) { if (err) return reject(err); resolve(res); }); }); } module.exports = run;
最初のバージョンとは大きく異なります:
まず、Promise を返します。 result.done が true の場合、解決します。 (result.value) 値。実行中にエラーが発生して捕捉された場合、その理由を拒否します。
2 番目に、thunkToPromise を使用してコールバック関数を Promise にラップし、then 関数を均一に追加します。ここで、 thunkToPromise 関数では、エラー第一原則に従っていることに注目してください。これは、コールバック関数の状況に対処するときを意味します。
// 模拟数据请求 function fetchData(url) { return function(cb) { setTimeout(function() { cb(null, { status: 200, data: url }) }, 1000) } }
成功すると、最初のパラメーターは null を返し、次のエラーがあることを示します。エラーの原因はありません。
最適化
2 番目のバージョンに基づいて、より簡潔かつエレガントにコードを作成しました。最終的なコードは次のとおりです。 #co
如果我们再将这个启动器函数写的完善一些,我们就相当于写了一个 co,实际上,上面的代码确实是来自于 co……
而 co 是什么? co 是大神 TJ Holowaychuk 于 2013 年 6 月发布的一个小模块,用于 Generator 函数的自动执行。
如果直接使用 co 模块,这两种不同的例子可以简写为:
// yield 后是一个 Promise var fetch = require('node-fetch'); var co = require('co'); function* gen() { var r1 = yield fetch('https://api.github.com/users/github'); var json1 = yield r1.json(); var r2 = yield fetch('https://api.github.com/users/github/followers'); var json2 = yield r2.json(); var r3 = yield fetch('https://api.github.com/users/github/repos'); var json3 = yield r3.json(); console.log([json1.bio, json2[0].login, json3[0].full_name].join('\n')); } co(gen);
// yield 后是一个回调函数 var co = require('co'); function fetchData(url) { return function(cb) { setTimeout(function() { cb(null, { status: 200, data: url }) }, 1000) } } function* gen() { var r1 = yield fetchData('https://api.github.com/users/github'); var r2 = yield fetchData('https://api.github.com/users/github/followers'); console.log([r1.data, r2.data].join('\n')); } co(gen);
是不是特别的好用?
以上がES6におけるGeneratorの自動実行について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

在es6中,可以利用“Array.isArray()”方法判断对象是否为数组,若判断的对象是数组,返回的结果是true,若判断对象不是数组,返回的结果是false,语法为“Array.isArray(需要检测的js对象)”。

es6中遍历跟迭代的区别是:遍历强调的是要把整个数据依次全部取出来,是访问数据结构的所有元素;而迭代虽然也是依次取出数据,但是并不保证取多少,也不保证把所有的数据取完,是遍历的一种形式。

在es6中,可用Object对象的is()方法来判断两个对象是否相等,该方法检测两个变量的值是否为同一个值,判断两个对象的引用地址是否一致,语法“Object.is(对象1,对象2)”;该方法会返回布尔值,若返回true则表示两个对象相等。

转换方法:1、利用“+”给数字拼接一个空字符,语法“数字+""”;2、使用String(),可把对象的值转换为字符串,语法“String(数字对象)”;3、用toString(),可返回数字的字符串表示,语法“数字.toString()”。

sort排序是es6中的;sort排序是es6中用于对数组的元素进行排序的方法,该方法默认不传参,按照字符编码顺序进行排序,排序顺序可以是字母或数字,并按升序或降序,语法为“array.sort(callback(a,b))”。

在es6中,assign用于对象的合并,可以将源对象的所有可枚举属性复制到目标对象;若目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性,语法为“Object.assign(...)”

改变方法:1、利用splice()方法修改,该方法可以直接修改原数组的内容,语法为“数组.splice(开始位置,修改个数,修改后的值)”;2、利用下标访问数组元素,并重新赋值来修改数组数据,语法为“数组[下标值]=修改后的值;”。

在es6中,import as用于将若干export导出的内容组合成一个对象返回;ES6的模块化分为导出与导入两个模块,该方法能够将所有的导出内容包裹到指定对象中,语法为“import * as 对象 from ...”。


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

WebStorm Mac版
便利なJavaScript開発ツール

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ホットトピック



