JS非同期プログラミングのいくつかの方法と違い
13042 ワード
前言
周知のように、
カルバック関数
calback関数とは、
Promise
Promiseは私たちがよく使っている非同期の問題を解決する方法です.コールバック関数のネストをチェーン呼び出しに変更できます.以上の複数のタスクは、次の例に変換できます.
私達の非同期の要求が順序A->>B->C->Dではなく、[A,B,C]->Dであれば、まずA、B、Cを並行して実行してからDを実行します.
Generator関数
Generator関数はES 6によって提供される非同期プログラミングソリューションであり、関数を実行するごとにリターンされるのはエルゴードオブジェクトであり、戻るオブジェクトはGeneratorのそれぞれの状態を順次巡回することができ、エルゴードオブジェクトの
まず例を示します
Generator関数を実行するたびにnextを使う必要があります.あなたは面倒くさいです.自動実行器が必要です.coモジュールは有名なプログラマTJ Holowaychukが2013年6月に発表したツールで、Generator関数の自動実行に使用されます.coモジュールを使用する場合、yieldの後ろにはThunk関数またはPromiseオブジェクトしかありません.co関数の実行が完了したら戻ってくるのはPromiseです.以下のとおりです
async関数
async関数は
asyncとPromise、Generator関数の比較
参考:ECMAScript 6阮一峰
転載先:https://juejin.im/post/5c95d9696fb9a070fa3769a9
周知のように、
Javascript
は「単一スレッド」言語であり、実際の開発においては、非同期論理の処理に直面しなければならない.非同期とは、一つのタスクを実行するには、AとBの二つの段階に分けられ、A段階を実行した後、もう一つのタスクを実行して結果を得てからB段階を実行するということです.非同期プログラミングには、callback
、Promise
、Generator
、async
、
、(callback hell)
のいくつかの一般的な方法があります.カルバック関数
calback関数とは、
Promise
を介して他の実行コードに伝達された、あるブロックで実行可能なコードの参照を指し、メイン関数によって呼び出された後、メイン関数に戻ります.function add(a, b, callback){
var num = a + b;
callback(num)
}
add(1, 2, function(num){
console.log(num); # 3
# ...
})
タスクのキューがある場合は、複数のタスクが含まれています.var readFile = require('fs-readfile-promise'); #
readFile(fileA, function(data) {
readFile(fileB, function(data) {
# ...
})
})
上述のように、n個のタスクが存在すると、n層を積層する必要があり、このコードは非常に冗長で結合度が高く、その中のある関数を修正すると、上下関数のコードブロックの論理に影響します.この場合は「コールバック地獄」と呼ばれています.Promise
Promiseは私たちがよく使っている非同期の問題を解決する方法です.コールバック関数のネストをチェーン呼び出しに変更できます.以上の複数のタスクは、次の例に変換できます.
function add(a, b){
return new Promise((resolve, reject) => {
var result = a+b;
resolve(result);
})
}
add(10, 20).then(res => {
return add(res, 20) # res = 30
}).then(res => {
return add(res, 20) # res = 50
}).then(res => {
// ...
}).catch(err => {
//
})
add関数が実行されるとPromise
に戻り、その結果はthen方法に入り、第一のパラメータはresolve
のPromise
の結果、第二のパラメータ(オプション)はreject
のthen
の結果となる.このようなチェーン方式の書き方は、各イベントのコールバック処理を効果的に分割し、コード構造がより明確になるように、コールバックされたロジックをcatch
方法で書くことができる.また、Promise
でエラーを処理できます.私達の非同期の要求が順序A->>B->C->Dではなく、[A,B,C]->Dであれば、まずA、B、Cを並行して実行してからDを実行します.
# Promise
const promises = [2, 3, 5].map(function (id) {
return getJSON('/post/' + id + ".json"); # getJSON Promise
});
Promise.all(promises).then(function (posts) {
# promises Promise
# posts , Promise
# D
}).then(res => {
//...
}).catch(function(reason){
//...
});
しかし、Promise
のコードには、new Promise
によって包装された関数のような余分なコードがあります.then
、catch
、next
があります.Generator関数
Generator関数はES 6によって提供される非同期プログラミングソリューションであり、関数を実行するごとにリターンされるのはエルゴードオブジェクトであり、戻るオブジェクトはGeneratorのそれぞれの状態を順次巡回することができ、エルゴードオブジェクトの
function
方法で関数を実行する必要がある.まず例を示します
function* foo() {
yield 'stepone';
yield 'steptwo';
return 'stepthree';
}
var _foo = foo();
_foo.next(); #{value: 'stepone', done: false}
_foo.next(); #{value: 'stepone', done: false}
_foo.next(); #{value: 'stepone', done: false}
Generatorには3つの特徴があります.関数名は*
の後にyield
を追加する必要があります.関数の内部にnext
があります.外部実行にはreturn
メソッドを呼び出す必要があります.各yieldは、彼女の後に付いている値をオブジェクトの戻りとして包み、返したオブジェクトには、done
に戻り、true
にGenerator
に戻るまで、戻り値と関数の実行状態が含まれる.Generator関数を実行するたびにnextを使う必要があります.あなたは面倒くさいです.自動実行器が必要です.coモジュールは有名なプログラマTJ Holowaychukが2013年6月に発表したツールで、Generator関数の自動実行に使用されます.coモジュールを使用する場合、yieldの後ろにはThunk関数またはPromiseオブジェクトしかありません.co関数の実行が完了したら戻ってくるのはPromiseです.以下のとおりです
var co = require('co');
var gen = function* () {
var img1 = yield getImage('/image01');
var img2 = yield getImage('/image02');
...
};
co(gen).then(function (res){
console.log(res);
}).catch(err){
#
};
coモジュールのタスクの並列処理は、複数のタスクを並列に実行してから次のステップに進みます.#
co(function* () {
var res = yield [
Promise.resolve(1),
Promise.resolve(2)
];
console.log(res);
}).then(console.log).catch(onerror);
#
co(function* () {
var res = yield {
1: Promise.resolve(1),
2: Promise.resolve(2),
};
console.log(res);
}).then(console.log).catch(onerror);
Promise
関数は、書き方においてco
よりも簡潔で論理的に明確であるが、この最適化を解決するために、async
関数が追加的に実行される必要がある.async関数
async関数は
Generator
関数のシンタックス飴です.var co = require('co');
var gen = function* () {
var img1 = yield getImage('/image01');
var img2 = yield getImage('/image02');
...
};
co(gen).then(function (res){
console.log(res);
}).catch(err){
#
};
****
# Generator
var gen = async function () {
var img1 = await getImage('/image01');
var img2 = await getImage('/image02');
return [img1, img2];
...
};
gen().then(res => {
console.log(res) # [img1, img2]
});
Generator
関数と比較して、async
の関数の書き方の違いはasync
の代わりに*
、await
がyield
の代わりになっています.async
はアクチュエータを備えています.より良い適応性を持ち、await
の後にPromise
であっても良いし、元のタイプの値であっても良い.また、async
関数はPromise
を返しています.私たちのより良い処理の戻り値になります.async function gen() {
return '111';
# return await '111';
};
gen().then(res => {
console.log(res) # 111
});
直接return値であれば、この値は自動的にthenメソッドのコールバック関数の値になります.async function gen() {
var a = await getA();
var b = await getB();
return a + b;
};
gen().then(res => {
console.log(res)
});
async
関数によって返されたPromise
は、関数の体内のすべてのawait
の後のPromise
オブジェクトが実行された後、またはreturn
または
の後に状態が変化する必要がある.つまり、async
内の非同期動作が全部終了してこそ、メインタスクに戻り、then
方法では、メインタスクを継続して実行することができるということです.# 1
async function gen() {
await new Promise((resolve, reject) => {
throw new Error(' ');
})
};
gen().then(res => {
console.log(res)
}).catch(err => {
console.log(err) #
});
# 2: , await await
async function gen() {
try{
await new Promise((resolve, reject) => {
throw new Error(' ');
})
}catch(e){
console.log(e); #
}
return Promise.resolve(1);
};
gen().then(res => {
console.log(res) # 1
});
エラー処理は上記の通りです.async function gen() {
#
let result = await Promise.all([getName(), getAddress()]);
return result;
#
let namePromise = getName();
let addressPromise = getAddress();
let name = await namePromise;
let address = await addressPromise;
return [name, address];
};
gen().then(res => {
console.log(res); # , getName getAddress
})
複数の非同期タスクは互いに依存関係がなく、併発が必要な場合は、上記の2つの方法で書くことができます.asyncとPromise、Generator関数の比較
function chainAnimationsPromise(elem, animations) {
# ret
let ret = null;
# Promise
let p = Promise.resolve();
# then ,
for(let anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
});
}
# Promise
return p.catch(function(e) {
#
}).then(function() {
return ret;
});
}
Promise
は地獄の逆転問題をよく解決しましたが、コードの中には意味に関係のないthen
、catch
などがたくさんあります.function chainAnimationsGenerator(elem, animations) {
return co(function*() {
let ret = null;
try {
for(let anim of animations) {
ret = yield anim(elem);
}
} catch(e) {
#
}
return ret;
});
}
Generator
関数は、関数を実行するために自動アクチュエータを必要とし、yield
の後はPromise
オブジェクトまたはThunk
関数だけである.async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(let anim of animations) {
ret = await anim(elem);
}
} catch(e) {
#
}
return ret;
}
async
関数の実装は最も簡潔であり、最も意味に合致し、意味不関連コードはほとんどない.Generator
と比較して、プログラマがもう1つのアクチュエータを提供する必要がなく、async
自体が自動的に実行し、簡潔に使用するのに便利である.参考:ECMAScript 6阮一峰
転載先:https://juejin.im/post/5c95d9696fb9a070fa3769a9