同期と非同期
同期とは、コードが1フレームで実行されることを意味し、非同期とは、何かが完了するまで待ってから実行することを意味します。
console.log("aaa");
for(var i=0;i<;i++){
}
console.log("bbb");//
同期 ランの終了を待つのを止め、次のランを続行します。
console.log("aa");
setTimeout(function(){
console.log("bb");
},5000)
console.log("cc"); //
非同期操作とは、1つのコンテンツが完了するのを待ってから、後のコンテンツを続けて実行することを意味します。
一般的な非同期イベント:
ロード・イベント、setTimeout、setInteral、requestAnimationFrame()
onloadやonclickなどのコードを多用すると、コールバック地獄を引き起こしやすくなります。そこで使えるのがプロミスです。
約束
非同期パターンを分散して処理します。
var p=new Promise(function(resolve,reject){
var img=new Image();
img.src="./img/17.jpg";
img.onload=function(){
resolve(img);
}
img.onerror=function(){
reject(img.src+"アドレスエラー");
}
})
p.then(function(a){
console.log(a);//resolveを実行してこの関数を実行する
},function(b){
console.log(b);//実行拒否でこの関数を実行する
})
promiseの関数は2つの引数を持ち、どちらも上のコードと同じように、1つは読み込みに成功したときに呼び出されるresolve、もう1つは読み込みに失敗したときに呼び出されるrejectです。
Promiseにはthenメソッドがあり、2つのパラメータを持ちます。1つ目のパラメータはこの関数を実行するresolveの実行、2つ目のパラメータはこの関数を拒否するrejectの実行です。
p.then(function(a){
console.log(a);//resolveを実行してこの関数を実行する
}).catch(function(b){
console.log(b);//実行拒否でこの関数を実行する
})
また、thenとcatchを使用することができます同じの使用を記述するには、thenコール関数の戻り値を使用することもできます再びthenを呼び出します。
new Promise(function (resolve, reject) {
var img1 = new Image();
img1.src = "./img/3-.jpg";
img1.onload = function () {
resolve(img1);
};
})
.then(function (img) {
arr.push(img);
return new Promise(function (resolve, reject) {
var img2 = new Image();
img2.src = "./img/4-.jpg";
img2.onload = function () {
resolve(img2);
};
});
})
.then(function (img) {
arr.push(img);
return new Promise(function (resolve, reject) {
var img3 = new Image();
img3.src = "./img/5-.jpg";
img3.onload = function () {
resolve(img3);
};
});
});
Promiseはすべての配列を一律に扱い、リストを返すallメソッドを提供します。
Promise.all(arr).then(function(list){
list.forEach(item=>{
console.log(item.src);
})
プロミスにはレースメソッドもあります。
Promise.race(arr).then(function(img){
console.log(img);//非同期リストで最初に終了したものが実行される。
プロミスが連続できるかどうか
var p=new Promise(function(resolve,reject){
resolve(1);
});
p.then(function(a){
console.log(a);// ここでリターンPromiseオブジェクトがなければ、次の実行を続ける。
// 次に実行されるのは、やはり現在のプロミス・オブジェクトである。
});
p.then(function(){
})
コードの実行順序
thenメソッドもcatchメソッドも、Promiseオブジェクトのメソッド自体は非同期です。
promiseオブジェクトでは、thenとcatchが非同期である以外はすべて同期です。
console.log("a");
new Promise(function(resolve,reject){
console.log("b");
resolve(1);
console.log("c");
}).then(function(a){
console.log("d");
}).then(function(){
console.log("e");
})
console.log("f");
//abcfde
プロミスにおけるresolveとrejectの実行の干渉
実行できるのは1つだけです。
function getImage(src) {
return new Promise(function (resolve, reject) {
var img1 = new Image();
img1.src = src;
img1.onload = function () {
resolve(img1);
reject(img1.src+"アドレスエラー");
};
});
}
非同期とawait
非同期関数は、実行後にプロミスオブジェクトを返します。
awaitは非同期関数にしか書けません。
waitはプロミスオブジェクトの非同期待ちだけを扱うことができます。
非同期関数で return を使って返されたものは、then を使って取り出すことができます。
function getImage(src) {
return new Promise(function (resolve, reject) {
var img1 = new Image();
img1.src = src;
img1.onload = function () {
resolve(img1);
};
});
}
async function loadImages(){
var arr=[];
for(var i=3;i<30;i++){ await getImage("./img/"+i+"-.jpg").then(function(img){
arr.push(img);
})
マクロタスク、ミクロタスク
非同期と同期の両方がタスクを完了させています。
同期タスクは行ごとに実行
非同期タスクは固定時間にも非固定時間にも存在します。
setTimeout、setInterval、requestAnimationFrame、promise はすべて固定時間です。
ファイルやイメージの読み込みは固定時間ではありません。
setTimeout setInterval はマクロ・タスクです。
プロミスのマイクロタスク
マクロタスクは、現在のタスクを次のタスク列の先頭に移動させるタスクです。
マイクロタスクとは、現在のタスクの内容を現在のタスク列の最下端に移動して実行すること
Promise.resolve().then(function(){
setTimeout(function(){
console.log("b");
},0)
})
setTimeout(function(){
Promise.resolve().then(function(){
console.log("a");
})
},0)
マクロタスク内のマイクロタスクは、マイクロタスク内のマクロタスクよりも優先されます;
マイクロタスク内のマイクロタスクはマイクロタスクより優先されます
以下のコードの実行順序を理解してください。
console.log(1);//1
new Promise(function (res, rej) {
console.log(2);//2
res();
})
.then(function () {
console.log(3);//5
Promise.resolve().then(function () {
console.log(5);//6
setTimeout(function () {
console.log(6);//15
Promise.resolve().then(function () {
console.log(7);//16
});
setTimeout(function () {
console.log(8);//18
}, 0);
}, 0);
});
})
.then(function () {
console.log(4);//7
});
setTimeout(function () {
console.log(9);//8
new Promise(function (res) {
res();
console.log(10);//9
}).then(function () {
console.log(11);//10
});
});
Promise.resolve().then(function () {
setTimeout(function () {
Promise.resolve().then(function () {
console.log(12);//14
});
console.log(13);//13
}, 0);
});
setTimeout(function () {
setTimeout(function () {
setTimeout(function () {
Promise.resolve().then(function () {
console.log(14);//20
});
console.log(15);//19
}, 0);
console.log(16);//17
}, 0);
console.log(17);//11
}, 0);
console.log(18);//3
new Promise(function (res) {
console.log(19);//4
setTimeout(function () {
console.log(20);//12
}, 0);
});