Core JavaScript-04.コールバック関数


1πコールバック関数は何ですか.
別のコードのパラメータに制御権を渡し、そのパラメータの関数に制御権を渡します.
コールバック関数を許可するコードは、自身の内部ロジックに基づいて適切な時点でコールバック関数を実行します.
📚 map関数によるコールバック関数の解析
[1,2,3].map(function(currentValue, index) {
	console.log(currentValue, index); 
});


Array.prototype.map(callback[, thisArg])
callback: function(currentValue, index, array)
Arrayプロトタイプにおけるmap法は上記構造からなる.
mapメソッドは、コールバック関数を最初のパラメータとして受信します.
2番目の省略可能なパラメータは、コールバック関数の内部でthisと識別されるターゲットを指定することができる.(thisArgを省略すると、グローバルオブジェクトがバインドされます.)
配列内のすべての要素を最初から最後まで1つずつ取り出し、コールバック関数を繰り返し呼び出し、コールバック関数の実行結果を収集して新しい配列を作成します.
コールバック関数の最初のパラメータには現在の値が含まれ、2番目のパラメータには現在の値インデックスが含まれ、3番目のパラメータには配列全体が含まれます.
💻 map関数を直接実現しましょう
Array.prototype.map = function (callback, thisArg) {
	let mapArr = [];
    for (let i = 0; i < this.length; i ++) {
    	let mapValue = callback.call(thisArg || window, this[i], i, this);
        mapArr[i] = mapValue;
    }
    return mapArr;
}
2πコールバック可能な関数は関数である.
 let obj = {
 	vals: [1,2,3],
    logValues: function(v,i) {
    	console.log(this,v,i);
    }
 }
 
 
 [4,5,6].forEach(obj.logValues);
obj.logValueはobjオブジェクトのメソッドとして定義される.
このメソッドをforEach関数のコールバック関数として渡します.
objを使う方法を直接伝えるのではなく、objです.valuesが指す関数のみが渡されます.
したがって、objと直接関連付けられていないため、グローバルオブジェクトの表示につながります.
オブジェクトのメソッドを関数のパラメータに渡しても、最終的にはメソッドではなく関数にすぎません.
📝 コールバック関数で特定のthisをバインドする場合はbindメソッドを使用します.
[4,5,6].forEach(obj.logValues.bind(obj)); //obj 객체를 this로 바인딩한 경우
3πコール地獄と非同期制御
地獄
コールバック関数を匿名関数に渡すプロセスを繰り返し、コードのインデント深さに耐えられない
通常、イベント処理やサーバ通信などの非同期タスクを実行する場合に発生します.
🚀 例題を通じてcallback地獄から釈放する方法を理解しましょう.
💣 地獄
setTimeout(function (val) {
	let text = val;
    setTimeout(function(val) {
    	let text += val;
        setTimeout(function(val) {
    		let text += val;
            console.log(text); // aabbcc
    	}, 10, 'cc' )
    }, 10, 'bb' )
}, 10, 'aa')
settimeoutコールバックでsettimeoutを使用してコールバックを複数回ネストします.
デップはますます深くなって、あなたの毒性は最も悪い!!⚠️⚠️⚠️
💡 コールバック地獄解決1-変換記名関数
let text = '';

const test1 = function(val) {
	text += val;
    setTimeout(test2, 10, 'bb')
    
}

const test2 = function(val) {
	text += val;
    setTimeout(test3, 10, 'cc')
}

const test3 = function(val) {
	text += val;
    console.log(text); //aabbcc
}

test1('aa');
記名関数の使用は可読性の問題をある程度解決したようだが,同様に使い捨て関数を複数回使用するため面白くない.
💡 callback地獄解決2-Promise
const test = function (name) {
	return function(prev = '') {
    	return new Promise(function(resolve) {
        	setTimeout(function() {
            	let text = prev + name;
                resolve(text);
            }, 10)
        })
    }
} 


test('aa')()
	.then(test('bb'))
    .then(test('cc')); // aabbcc
ES 6のPromiseを利用する方法です.
new演算子とともに呼び出されたPromiseパラメータに渡されるコールバック関数は、呼び出されるとすぐに実行されますが、resolve、execute関数の内部に構文がある場合、そのうちの1つが実行されるまでthenまたはエラー構文(catch)には移動しません.
💡 callback地獄解決3-Generator
const test = function (prev, name) {
	setTimeout(function() {
    	testGenerator.next(prev+name);
    }, 10);
}

const generator = function* () {
	let test1 = yield test('', 'aa');
    let test 2 = yield test(test1, 'bb');
    let test3 = yield test(test2, 'cc');
}

const testGenerator = generator();
testGenerator.next();
ES 6のジェネレータを使用しました.
*付きの関数はジェネレータです.generator関数を実行してiteratorを返します.iteratorにはnextというメソッドがあります.
nextメソッドを呼び出すと、generator関数の内部に最初に現れた完成品で関数の実行が停止します.
nextメソッドが再び呼び出されると、前に停止した部分から開始し、表示された完成品で関数の実行を停止します.
すなわち、非同期操作が完了したときにnextが呼び出されると、ジェネレータ関数の内部ソースは上から下へ順に実行されます.
💡 コール地獄解決4-Promise+Async/Await
const test = function(name) {
	return new Promise(function(resolve) {
    	setTimeout(function() {
        	resolve(name);
        }, 10);
    })
}

const maker = async function() {
	let text = '';
    
   let addText = async function (name) {
   		text += test(name);
   }
   
   await addText('aa')
   await addText('bb')
   await addText('cc')
   
   console.log(text); // aabbcc
}
ES 8のasync/awaitを使用しました.
非同期操作を実行する関数の前にasyncをマークし、関数の内部に実際の非同期操作が必要な各位置にawaitをマークするだけで、後の内容を自動的にpromiseに変換できます.
この内容が解決してから、次のステップに進むことができます.
すなわち,承諾したthenのような効果を得ることができる.
📚 整理する
📌 コールバック関数は、パラメータを他のコードに渡し、同時に制御権を委任する関数です.
📌 制御権を受け取ったコードは、コールバック関数が呼び出された時点を自動的に判断します.
📌 制御権を渡すコードは、コールバック関数を呼び出すと、パラメータに渡される値の順序が決定されます.
📌 制御権を受け入れるコードは、コールバック関数のthisが何を望んでいるかを決定することができる.(bindメソッド)
📌 メソッドをパラメータとしてどの関数に渡しても、最終的には関数として実行されます.
📌 非同期制御のためにコールバック関数を使用すると、コールバック地獄に陥る.ソリューションにはPromise、Generator、async/awaitなどがあります.