仕事は轤?上芸なり~と勤しむ轤?上芸人にも分かるように解説をさせて頂きた縺?候
(勤しむところはソコではない)
///promise/async/await 非同期関謨?
【ES6】 JavaScript初心者でも繧?かるPromise講蠎? - Qiita
(勤しむところはソコではない)
///promise/async/await 非同期関謨?
【ES6】 JavaScript初心者でも繧?かるPromise講蠎? - Qiita
https://rightcode.co.jp/blog/information-technology/javascript-promise
https://rightcode.co.jp/blog/information-technology/javascript-async-await
http://www.tohoho-web.com/ex/promise.html
https://sbfl.net/blog/2016/07/13/simplifying-async-code-with-promise-and-async-await/
https://qiita.com/niusounds/items/37c1f9b021b62194e077
https://qiita.com/soarflat/items/1a9613e023200bbebcb3
非同期関数は処理の順蠎?を制御できない問題があった、そこ縺?Promise
↓
Promise オブジェクト縺? then(ok_callback, ng_callback) というメソッドを持ちます。
then() 縺?Promise が成功または失敗になるまで処理を藹??け流し、
処理を.then()で軆??げ順番を確臀??することが可閭?
成功時縺? ok_callback を、失敗時縺? ng_callback をコールバック関数として呼び出します
.then() は第一引数に成功時のコールバック関数、第臀??引数に失敗時のコールバック関謨?
.catch(ng_callback) は、.then(undefined, ng_callback) と同じ諢?蜻?
.catch() は処理中に発生した throw をキャッチできる
ES2018(ES9) では、.finally() がサポートされました
function aFunc3(data) {
return new Promise(function(okCallback, ngCallback) {
setTimeout(function() {
if (Math.random() < 0.30) {
ngCallback(new Error('ERROR!'));
} else {
okCallback(data * 2);
}
}, Math.random() * 1000);
});
}
function sample_finally2() {
aFunc3(100).then((data) => {
console.log(data);
return aFunc3(data);
})
.then((data) => {
console.log(data);
return aFunc3(data);
})
.then((data) => {
console.log(data);
throw new Error('ERROR!!!');
})
.catch((e) => {
console.log("catch");
console.log(e);
})
.finally(() => {
console.log('*** Finally ***');
});
}
//200 400 800 catch Error:ERRROR!!! *** Finally ***
Promise.all() は配列で指定された全て縺?Promiseタスクを待ち全てが完了した時点縺? .then()を呼縺?
Promise.race()ならいずれか縺?Promise
function sample_all() {
p1 = taskA();
p2 = taskB();
Promise.all([p1, p2]).then(() => {
console.log("taskA and taskB are finished.");
});
}
↓
ES2017 では、async/await がサポートされました
async 縺? await を用いることで、Promise に対応した非同期関数を、同期関数の觸??にシンプルに呼び出すことが可能となります
同期関数の觸??に呼び出したい非同期関数を呼び出す際縺? await をつけます。await を呼び出す関数縺? async をつけます
async function sample_async_await_with_catch() {
var val = 100;
try {
val = await aFunc3(val);
console.log(val);
val = await aFunc3(val);
console.log(val);
val = await aFunc3(val);
console.log(val);
} catch (e) {
console.log(e);
}
}
■コールバック関謨?
広い定義でいうと「高髫?関数に渡すための関数」
「関数を藹??け藹??る関数」は「高髫?関数」、つまりhello()がコールバック関謨?
// 関数を2回実行する関数・??!
function doTwice(func) {
func(); // 1回逶?Hello!
func(); // 2回逶?Hello!
}
// あいさつするだけの関謨?
function hello() {
console.log('Hello!');
}
// あいさつを2回実行する
doTwice(hello);
========================================
もっと詳し縺?、もっと分かり易縺?、どう使うか↓
https://knowledge.sakura.ad.jp/24890/
https://jsprimer.net/basic/async/
https://dev.classmethod.jp/articles/javascript-asynchronous-processing/
■処理の軆??がり
1)コールバック関謨?
ある関数の処理が終繧?れば次のコールバック関数を呼ぶという指定がそれ
歴史的にはエラーファーストコールバック・??のルール・??
処理が失敗した場合は、コールバック関数縺?1番目の藹??数にエラーオブジェクトを渡して呼び出す
処理が成功した場合は、コールバック関数縺?1番目の藹??数に縺?nullを渡し、2番目以降の藹??数に成功時の軆??果を渡して呼び出す
fs.readFile("./example.txt", (error, data) => {
2)Promise(非同期処理に対するPromise→順番を合繧?せる諢?味では同期処理ではと思う?JSはシングルスレッドかつ非同期という糞?仕様)
ある関数の処理が終繧?れ縺?Promiseオブジェクトを返す
JSがシングルスレッドだが 処理を一定の単位ごとに分け処理を切り替えながら実行する並鐔??処理(concurrent)の臀??様のため 順蠎?を考慮する必要がある
非同期処理の藹??行中にとても重たい処理があると非同期処理の切り替えが遅れる
Promiseオブジェクト縺?3つの内部状態を持ちます。
pending(保留): まだ非同期処理は軆??繧?っていない(成功も失敗もしていない)
fulfilled(成功): 非同期処理が正常に軆??了した
rejected(拒否・??: 非同期処理が失敗した
初期状態縺?pendingで、一蠎?fulfilledまた縺?rejectedになったらそれ以降は状態は藹??繧?らず、非同期処理の軆??了時に鐔??す値もそれ以降は藹??繧?らない
Promiseのコンストラクターは関数を引数に藹??って、その関数がさら縺?2つの関数を引数に藹??る
1番目の関数・??resolve)に藹??数を渡して藹??行すると状態がfulfilledになり、引数の値縺?Promiseオブジェクトが保持する値になる
2番目の関数・??reject)に藹??数を渡して藹??行すると状態がrejectedになり、引数の値縺?Promiseオブジェクトが保持する値になる
関数が例外を投げた場合も状態がrejectedになり、投げた値がPromiseオブジェクトが保持する値になる、throwする値をrejectedに渡して藹??行した時と同じ
then()縺?2つの関数を引数に藹??り、Promiseの状態がfulfilledになったら1番目の関数が、rejectedになったら2番目の関数が実行されます。
then()縺?1番目の藹??数が関数でなけれ縺?identity function(入力値をそのまま鐔??す関数・??が代繧?りに使繧?れます
2番目の藹??数が関数でなけれ縺?thrower function(入力値を例外として投げる関数・??が代繧?りに使繧?れます
catch()縺?1番目の藹??数縺?identity functionを指定したthen()と同じ
上の挙動をオレオ繝?PromiseをYakusokuで臀??っているので分かり易い https://knowledge.sakura.ad.jp/24890/
なお、本質としてはコレ、下記ソースが決まりの觸??れ、ひな形としてヤリ慣れるしか
1)時間が觸??かる処理をPromise化して順序立てよう
2)成功と失敗のコールバックを指定しよう
//処理にコールバック関数を入れて成功と失敗時の型で軆??える
function dummyFetch(cmt, callBack) {
setTimeout(() => {
if (cmt.startsWith("/success")) {
callBack(null, { body: `Response body of ${cmt}` });
} else {
callBack(new Error("Bad"));
}
}, 1000 * Math.random());
}
//プロミスを入れるためラッパーを関数にかます
function aaaFilePromise(cmt) {
return new Promise((resolve, reject) => {
dummyFetch(cmt, (err, data) => {
if (err) {
reject(err); // 失敗: 内部状態をrejectedにする
}
else {
resolve(data); // 成功: 内部状態をfulfilledにする
}
});
});
}
//プロミスチェーンでのフロ繝?
aaaFilePromise("/success/passwd")
.then((data) => { // 読み出しに成功したらresolve()に渡した値が引数として渡される
console.log("1", data);
//return 'next';//テキストがあってもな縺?ても次縺?thenに鐔??縺?、省略でもテキストでも第臀??引数関数に鐔??縺?成功蛛?
return aaaFilePromise("/etc/text");//エラーで次縺?thenの失敗側の第二引数関数にきっちり行縺?
})
.then((data) => {
console.log("2", data);
return aaaFilePromise("/success/shadow1");
}, (data) => {
console.log("2e", data);
return aaaFilePromise("/success/shadow2");
})
.then((data) => {
console.log("3", data);
return aaaFilePromise("/etc/shadow");
})
.catch((err) => { // reject()に渡した値が引数として渡される
console.log("error", err);
});
then()/ catch()は、引数で渡された関数の戻り値から新た縺?Promiseオブェクトを作り、そのオブジェクトを返します。そのためメソッドチェーンが可閭?
引数に渡した関数の戻り値がPromiseオブジェクトの場合はそのオブジェクトをそのまま鐔??す、そうでなければ戻り値をPromiseで包んで鐔??す
エラーでキャッチに饅??ぶ訳ではなく次縺?then隨?2引数関数に饅??んでいる、省略縺?catchに鐔??っているように鐔??えるだけ
dexieやPWAでの觸??供があり使う(処理を順序立てて使うようプログラムを組む時縺?
dexie: db.schedule.where('site').equals('sche').first().then(function(records) {
pwa: caches.keys().then(function(keyList){
return Promise.all(keyList.map(function(key){
3)async / await
promiseは順番決めができたがasync/awaitは順番を扱う処理もできる
3)async / await
promiseは順番決めができたがasync/awaitは順番を扱う処理もできる
setTimeout/setIntevalがプロミスチェーンだけでは時間を止められない
シングルスレッドから似非スレッドで分離し非同期になるから、awaitを入れると同期する↓
const wait = (sec) => {
シングルスレッドから似非スレッドで分離し非同期になるから、awaitを入れると同期する↓
const wait = (sec) => {
return new Promise((resolve, reject) => { setTimeout(resolve, sec*1000); });
};
async function arrKick_async(arr) {
for(let i=1; i<=num_arr; i++){
arr = await kickPromise(arr);
await wait(2);
}
}
}
arrKick_async(arr);
4)コールバック地獄
結局コールバック地獄が扱いやすい(スレッドの切り替えがなければ同期ができる)、最近縺?JSフレームワークは全驛?Promise化しているらしいが
■Javascript
https://www.bangboo.com/cms/blog/page_325.html
========================================
JSネイティブ縺?Promise縺?asyncが混ざった場合は同期しない、then()すら超えて縺?る↓
4)コールバック地獄
結局コールバック地獄が扱いやすい(スレッドの切り替えがなければ同期ができる)、最近縺?JSフレームワークは全驛?Promise化しているらしいが
例)キャッシュを保存し、そのステータスを藹??るよう縺?AsyncやPromiseで臀??存待ちの順番をにしても、待たない
//隙間がない縺?1度エラーだとエラーになりっぱなし
let num_cache;
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
num_cache = getCacheStatus();
if(num_cache == 0 || !num_cache){
//setTimeoutで隙間があっても関数スレッドの鐔??り値を代入するスレッド切替時に、返り値を待つスレッドの方は次の処理に進んでしまいIF判藹??ができない
let s = setTimeout(function(){
let num_cache1 = getCacheStatus();
if(num_cache1 == 0 || !num_cache1){
s = setTimeout(function(){
let num_cache2 = getCacheStatus();
if(num_cache2 == 0 || !num_cache2){
s = setTimeout(function(){
let num_cache3 = getCacheStatus();
if(num_cache3 == 0 || !num_cache3){
s = setTimeout(function(){
let num_cache4 = getCacheStatus();
if(num_cache4 == 0 || !num_cache4){
//Func返り値やPromiseやAsyncでのスレッドの切り替えがないDOMの判藹??であれば臀??手縺?い縺?
let s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == 'none'){
s = setTimeout(function(){
getCacheStatus();
if(document.getElementById('mes_filenames').innerHTML == '<?php echo $lang_page->install_none; ?>'){
function getCacheStatus(){
let num_caches = 0;
let num_success = 0;
caches.keys().then(function(keyList){
return Promise.all(keyList.map(function(key){
caches.open(key).then(function(cache) {
cache.matchAll().then(function(response) {
document.getElementById('mes_filenames').innerHTML = '';
let s;
let o;
for(const value of response){
s = value.status;
o = value.ok;
document.getElementById('mes_filenames').insertAdjacentHTML('afterbegin', value.url + '<br>');
if(s == '200' && o){
num_success++;
}
num_caches++;
}
if(num_caches > 0){
document.getElementById('mes_progress_rate').innerHTML = 'Progress: ' + num_success / num_caches * 100 + '%';
}else{
document.getElementById('mes_filenames').innerHTML = 'None';
}
});
});
}));
});
return num_caches;
}
===============
thenの入れ子だと親の部分だけ先に進んでしまう、入れ子ダメで親子を作れば親→子の臀??方方向で藹??で軆??繧?るトーナメント構造縺?(上がらない)
test1().then((result) => {
test2().then((result) => { //fuok });
thenの入れ子だと親の部分だけ先に進んでしまう、入れ子ダメで親子を作れば親→子の臀??方方向で藹??で軆??繧?るトーナメント構造縺?(上がらない)
test1().then((result) => {
test2().then((result) => { //fuok });
})then(function() これは入れ子
↓
test1().then((result) => {
test2().then((result) => {
↓
test1().then((result) => {
test2().then((result) => {
//fuok
})then(function(){ //fuok2 }); これでトーナメント構造
})catch(function(e)
===============})then(function(){ //fuok2 }); これでトーナメント構造
})catch(function(e)
promiseチェーン縺?then豈?にに欲しい引数を出すが、複数であればそれらの藹??数をthenに渡せない、下記1は饅??逶?
1)thenで臀??つの藹??数になるようにロジックを組む(thenのトーナメント構造、一髫?層臀??で藹??数に入れる等)
1)thenで臀??つの藹??数になるようにロジックを組む(thenのトーナメント構造、一髫?層臀??で藹??数に入れる等)
}).then(function(response){
return [response.json(), arr_del];
}).then(function(v) {
json = v[0]; arr = v[1];
2)callback縺?resolveに配列を使う縺?OK、オブジェクトでもいいかも
2)callback縺?resolveに配列を使う縺?OK、オブジェクトでもいいかも
function dummyFetch(cmt, callBack) {
if(Array.isArray(cmt){
var p = cmt[0];
var s = cmt[1];
}else{
var p = cmt;
var s = 1;
}
setTimeout(() => {
if (p.startsWith("/success")) {
var r = [p, ++s];//これ不藹??[p, s++]
callBack(null, r);
} else {
callBack(new Error("Bad"));
}
}, 1000 * Math.random());
}
function aaaFilePromise(cmt) {
return new Promise((resolve, reject) => {
dummyFetch(cmt, (err, data) => {
if (err) {
reject(err);
}
else {
if(Array.isArray(data){
var p = data[0];
var s = data[1];
}else{
var p = data;
var s = 1;
}
resolve([p, s]); // 成功: 内部状態をfulfilledにする
}
});
});
}
Promise化していない関数を使いたいが、そのまま使うかthen化できるようにするか?
1)谺?thenに進みたい元Funcの処理とし縺?resolveの鐔??り値に入れる、ダメなら省略可だがreject()に渡しcatchする
2)谺?thenには適藹??でもいいの縺?returnで進む
2)谺?thenには適藹??でもいいの縺?returnで進む
function test1 () {
return new Promise((resolve, reject) => {
const a = 1;
const b = 2;
resolve([a, b]);
})
}
test1().then((result) => {
console.log(result[0]); // 1
console.log(result[1]); // 2
return 'go next';
return 'go next';
}).then(function(){
エラー繝?ンドリングしたい、よ縺?繧?からんが下記で動作に違いがでた、reject縺?JSがエラーを吐いた
1)catchさせるに縺?throw new Errorし、alertを出す
2)catchはしないが次縺?thenには移動させないためreturn false
1)catchさせるに縺?throw new Errorし、alertを出す
2)catchはしないが次縺?thenには移動させないためreturn false
}).then(function(json){
if(json.init == 'Not appropriate access'){
throw new Error('Server warning');
}else if(json.init == 'No data'){
//reject("initiate!");
return false;
}else{
resolve(json);
}
resolve(json);
}
}).catch(function(error){
alert('Ooops: ' + error);
});
Promise.allを使って、3つ縺?promiseを同時に藹??行、allはすべての非同期処理がresolveされたタイミングで軆??果を返
Promise.all([test1, test2, test3]).then(function() {
console.log("Fourth");
もっと簡単縺? async, await, Promise - Qiita■Javascript
https://www.bangboo.com/cms/blog/page_325.html





