JavaScript非同期処理のいくつかの方法
32788 ワード
1.コールバック関数
コールバック(callback)は、1つの関数が1つのパラメータとして別の関数に渡され、その関数が実行された後に実行される.2つの関数f 1とf 2があり、f 2はf 1の実行結果を待っていると仮定し、f 1()->f 2();f 1が時間がかかる場合は、f 1を書き換え、f 2(矢印関数)をf 1のコールバック関数と書くことができます.
利点:簡単、便利、実用的.欠点:コールバック関数地獄を形成しやすい.非同期操作が1つしかない場合、コールバック関数で処理するのは全く問題ありません.しかし、複数のコールバック関数をネストすると、複数の非同期操作が強い結合を形成し、コードが混乱し、管理できないため、問題が大きくなります.このことを「コールバック関数地獄」(callback hell)と呼ぶ.
2.Promiseオブジェクト(推奨)
意味:Promiseは非同期プログラミングのソリューションで、利点:Promiseはチェーンプログラミングで、頭が痛いコールバック地獄問題を効果的に解決し、Promiseの結果は成功と失敗の2つの状態があり、非同期操作の結果だけが、現在どの状態であるかを決定することができ、外部のいかなる操作もこの状態を変えることができない.2.1共通API resolve非同期操作成功の結果reject非同期操作失敗の結果then実行Promise状態成功の操作catch実行Promise状態失敗の操作finally失敗の操作
2.2 Promise.all Promise.allメソッドは、複数のPromiseインスタンスを新しいPromiseインスタンスにパッケージするために使用されます.const p = Promise.all([p 1,p 2,p 3])pの状態はp 1,p 2,p 3によって決定され,二つの場合に分けられる.(1)p 1,p 2,p 3の状態のみがfulfilledとなり、pの状態がfulfilledとなる.このときp 1,p 2,p 3の戻り値は配列をなしてpのコールバック関数に渡される.(2)p 1,p 2,p 3のうちの1つがrejectedされる限り、pの状態はrejectedとなり、このとき最初のrejectされたインスタンスの戻り値はpのコールバック関数に渡される.
3.イベントリスニング
イベント駆動モードを使用すると、タスクの実行はコードの順序に依存せず、イベントが発生するかどうかに依存します.リスニング関数は、on,bind,listen,addEventListener,observeの例であり、f 1にイベントをバインドする(jquery書き方):f 1.on(‘done’,f 2);すなわち、f 1にdoneイベントが発生すると、f 2が実行される.
利点:理解しやすく、複数のイベントをバインドすることができ、各イベントは複数のコールバック関数を指定することができ、結合することができ、モジュール化の欠点を実現するのに有利である:プログラム全体がイベント駆動型になり、実行プロセスが不明確になる
4.Generator関数
意味:Generator関数はES 6が提供する非同期プログラミングソリューションであり、文法的挙動は従来の関数とは全く異なる.基本的な使い方:
特徴: functionキーワードと関数名の間にアスタリスクがあります. 関数体の内部でyield式を使用して、異なる内部状態を定義します. はnext法により各セグメント状態の戻り結果を取得し,上で4回に分けてGennarator関数を実行した.初めて、最初のyield関数の戻り結果を取得して一時停止し、done:falseは、関数内の状態がまだ実行されていないことを表します.2回目、同じ理屈.3回目はreturnの戻り結果を取得し、done:trueは関数内の状態が実行済みであることを示す.4回目は、関数内に実行可能な状態がなく、undfinedを返し、関数内の状態が実行済みであることを伝える.関数内にreturnがない場合、3回目にundfinedが返され、done:trueは関数内の状態が実行済みであることを示します.
5.async関数(推奨)
意味:async関数はES 2017規格に導入され、asyncは非同期操作をより便利にしたが、実は彼はGenerator関数の文法糖の基本的な使い方である.
説明: awaitコマンドはasync関数でのみ使用でき、通常の関数で使用するとエラーが表示されます. awaitの後ろには、get 1 returnから出たPromiseインスタンスなどのPromiseオブジェクトがあります.Promiseオブジェクトでない場合は、「111」を直接返すなど、対応する値を直接返します. Promiseオブジェクトが、値xでfulfilledされると、値x.Promiseオブジェクトが戻り、異常eでrejectedされると、異常e が投げ出す. async関数が返すPromiseオブジェクトは、内部のすべてのawaitコマンドの後のPromiseオブジェクトが実行されるまで待たなければ、ステータスが変更されません.await文の後ろにあるPromiseオブジェクトがreject状態になったり、returnに遭遇したりすると、async関数全体が実行を中断します. awaitはPromiseオブジェクトを待つとasync functionが実行を一時停止し、Promiseオブジェクト決議の後になってからasync functionが実行を継続する.前の非同期操作が失敗しても、後の非同期操作を中断しないでほしい場合.この場合、最初のawaitをtry...catch構造に配置することで、この非同期操作が成功するかどうかにかかわらず、2番目のawaitが実行されます.
利点:Generator関数に比べてasync関数は次の4つの改善点があります.内蔵エフェクタ:Generator関数の実行はnext()で毎回のモジュール実行を行わなければならない.asyncはエフェクタを持参し、普通の関数と同じように呼び出すだけで を実行できる.のより良い意味:asyncは関数に非同期操作があり、awaitは後続の式が結果を待つ必要があることを示します.戻り値はPromise:async関数の戻り値はPromiseオブジェクトで、thenメソッドで次の操作を指定できます.さらにasync関数は複数の非同期関数の操作と見なすことができ、パッケージされたPromiseオブジェクトであり、awaitコマンドは内部thenコマンドの構文糖、すなわちPromiseである.all()の使い方複数のawaitコマンドの後の非同期操作は、リレー関係が存在しない場合は、同時にトリガーすることが望ましい.
参考記事(侵入)
コールバック(callback)は、1つの関数が1つのパラメータとして別の関数に渡され、その関数が実行された後に実行される.2つの関数f 1とf 2があり、f 2はf 1の実行結果を待っていると仮定し、f 1()->f 2();f 1が時間がかかる場合は、f 1を書き換え、f 2(矢印関数)をf 1のコールバック関数と書くことができます.
function f1(callback){
setTimeout(() => {
let name = ' '
console.log(' ') // f1
callback(name)
}, 100);
}
f1((name)=>{
console.log(' '+name)
})
//
//
利点:簡単、便利、実用的.欠点:コールバック関数地獄を形成しやすい.非同期操作が1つしかない場合、コールバック関数で処理するのは全く問題ありません.しかし、複数のコールバック関数をネストすると、複数の非同期操作が強い結合を形成し、コードが混乱し、管理できないため、問題が大きくなります.このことを「コールバック関数地獄」(callback hell)と呼ぶ.
getData('XXX1', () => {
// callback
getData('XXX2', () => {
// callback
getData('XXX3', () => {
// callback
getData('XXX4', () => {
// callback
getData('XXX5', () => {
// callback
})
})
})
})
})
2.Promiseオブジェクト(推奨)
意味:Promiseは非同期プログラミングのソリューションで、利点:Promiseはチェーンプログラミングで、頭が痛いコールバック地獄問題を効果的に解決し、Promiseの結果は成功と失敗の2つの状態があり、非同期操作の結果だけが、現在どの状態であるかを決定することができ、外部のいかなる操作もこの状態を変えることができない.2.1共通API resolve非同期操作成功の結果reject非同期操作失敗の結果then実行Promise状態成功の操作catch実行Promise状態失敗の操作finally失敗の操作
//ES6 ,Promise , Promise 。
const p = new Promise(function(resolve,reject){
if(success){
resolve(' ')
}else{
reject(' ')
}
})
p.then(function (res) {
// resolve ,
},function (err) {
// reject ,
})
p.catch(function (err) {
// reject then() ,
})
p.finally(function(){
//
})
const p = new Promise((resolve, reject) =>{
setTimeout(() => {
let name = ' '
resolve(name)
}, 100);
});
p.then((res) => {
console.log(res)
})
2.2 Promise.all Promise.allメソッドは、複数のPromiseインスタンスを新しいPromiseインスタンスにパッケージするために使用されます.const p = Promise.all([p 1,p 2,p 3])pの状態はp 1,p 2,p 3によって決定され,二つの場合に分けられる.(1)p 1,p 2,p 3の状態のみがfulfilledとなり、pの状態がfulfilledとなる.このときp 1,p 2,p 3の戻り値は配列をなしてpのコールバック関数に渡される.(2)p 1,p 2,p 3のうちの1つがrejectedされる限り、pの状態はrejectedとなり、このとき最初のrejectされたインスタンスの戻り値はpのコールバック関数に渡される.
let p1 = new Promise((resolve, reject) => {
console.log('begin p1');
setTimeout(() => {
console.log('end p1');
resolve('p1');
}, 2);
});
p1.then(() => {
console.log('then p1');
})
let p2 = new Promise((resolve, reject) => {
console.log('begin p2');
setTimeout(() => {
console.log('end p2');
resolve('p2');
},3);
})
p2.then(() => {
console.log('then p2');
})
setTimeout(() => {
console.log('setTimeout: p3');
let p3 = Promise.all([p1, p2]).then((datas) => {
console.log('begin p3');
console.log('end p3');
});
p3.then(() => {
console.log('then p3');
});
},1);
console.log('mark p4');
// begin p1
// begin p2
// mark p4
// setTimeout: p3
// end p1
// then p1
// end p2
// then p2
// begin p3
// end p3
// then p3
3.イベントリスニング
イベント駆動モードを使用すると、タスクの実行はコードの順序に依存せず、イベントが発生するかどうかに依存します.リスニング関数は、on,bind,listen,addEventListener,observeの例であり、f 1にイベントをバインドする(jquery書き方):f 1.on(‘done’,f 2);すなわち、f 1にdoneイベントが発生すると、f 2が実行される.
function f1(){
settimeout(function(){
// f1
f1.trigger('done'); // , done , f2
},1000);
}
利点:理解しやすく、複数のイベントをバインドすることができ、各イベントは複数のコールバック関数を指定することができ、結合することができ、モジュール化の欠点を実現するのに有利である:プログラム全体がイベント駆動型になり、実行プロセスが不明確になる
4.Generator関数
意味:Generator関数はES 6が提供する非同期プログラミングソリューションであり、文法的挙動は従来の関数とは全く異なる.基本的な使い方:
function* helloGenerator() {
yield 'hello';
yield 'Generator';
return 'over';
}
let hw = helloGenerator();
hw.next() // {value:"hello",done:false}
hw.next() // {value:"Generator",done:false}
hw.next() // {value:"over",done:true}
hw.next() // {value:undfined,done:true}
特徴:
5.async関数(推奨)
意味:async関数はES 2017規格に導入され、asyncは非同期操作をより便利にしたが、実は彼はGenerator関数の文法糖の基本的な使い方である.
function get1(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1)
},2000)
})
}
async function getSet(){
const n = await get1()
//const n = await '111'
return n
}
getSet().then(console.log)
説明:
async function f() {
try {
await Promise.reject(' ');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let name = ' '
resolve(name)
}, 100);
});
}
async function test() {
let newData = await getData()
console.log(newData)
}
test()
//
利点:Generator関数に比べてasync関数は次の4つの改善点があります.
// getFoo(), getBar()
//
async function getSet(){
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
return [foo, bar]
}
//
async function getSet(){
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
return [foo, bar]
}
参考記事(侵入)