この広告は、90日以上更新していないブログに表示しています。
非同期な処理を同期的に書ける関数タイプが実装された。
「async」キーワードに続けて関数定義を書くと、async関数となる。
asyncfunction afn1(){}afn2 = async () =>{}obj ={ async afn3(){}}
async関数を呼び出すとプロミスが返される。
console.log( afn1() )// <Promise>
このプロミスは、async関数が終了するとその返り値で解決され、例外が起こると棄却される。
asyncfunction afn4( flag ){if ( flag )return'Yes'elsethrow'No'}afn4(true ).then( v => console.log( v ) )/// "Yes"afn4(false ).catch( v => console.log( v ) )/// "No"
ちなみに返り値にプロミスを返すと、その解決を待ってからその解決値をもってasync関数が返すプロミスは解決される。
asyncfunction afn5(){return Promise.resolve( 123 )}afn5().then( v => console.log( v ) )/// 123
await式はキーワード「await」とプロミス型値「p」を使って、「await p」の形で書くことが出来る。
await式は「p」(プロミスでなくともプロミスとしてラップされる)が解決するまで待ってその解決値を式結果として返す。
function delay( s ){// s秒後に解決するプロミスを返す関数returnnew Promise( ok => setTimeout( ok, s, `${s}秒経ったよ!` ) )}
asyncfunction afn6(){ console.log('スタート' )let message = await delay( 1 ) console.log( message )}afn6()/// "スタート" → "1秒経ったよ!"
async関数もプロミスを返すので、async関数の処理の待ち合いにも使える。
asyncfunction afn7(){for (let i = 0; i < 3; i++ ){ await afn6()}}afn7()/// "スタート" → "1秒経ったよ!" →/// "スタート" → "1秒経ったよ!" →/// "スタート" → "1秒経ったよ!"
つまり、プロミスを返す関数を利用するのにasync関数が良く使え、
async関数を利用するのにasync関数が良く使える。
例:キャッシュからファイルを返す関数 もし無ければフェッチしてファイルを取ってきてキャッシュに追加する
いままで:
function getTextFile( url ){return caches.open('test' ).then( cache => cache.match( url ).then( response =>{if ( !response ){return fetch( url ).then( response => cache.put( url, response ) ).then( () => getTextFile( url ) )}return response.text()} ) )}getTextFile('' ).then( t => console.dir( t ) )
ややこしい。
function spawn( gfn ){return ( ...args ) =>{const gen = gfn( ...args )returnnew Promise( ( resolve, reject ) =>{const step = v =>{const{ value, done} = gen.next(v) Promise.resolve( value ).then( done ? resolve : step ).catch( reject )} step()} )}}
getTextFile = spawn(function* ( url ){const cache = yield caches.open('test' )const response = yield cache.match( url )if ( !response ){ yield cache.put( url, yield fetch( url ) )return yield getTextFile( url )}return response.text()})getTextFile('' ).then( t => console.dir( t ) )
トリッキー。
async関数を使うと:
asyncfunction getTextFile( url ){const cache = await caches.open('test' )const response = await cache.match( url )if ( !response ){ await cache.put( url, await fetch( url ) )return await getTextFile( url )}return response.text()}getTextFile('' ).then( t => console.dir( t ) )
スマートに書ける。
例:フィボナッチ数列を計算する
普通に書くと:
function calcFibAry( size ){let p = 1, q = 1const ary =[ p, q]while ( ary.length < size ){[ p, q] =[ q, p + q] ary.push( q )}return ary}console.log( calcFibAry( 1e7 ) )
いつまでもレンダリング等へ制御が移らず固まる。
ジェネレータとrequestIdleCallbackを使うと:
function *calcFibAryStep( size ){let p = 1, q = 1const ary =[ p, q]while ( ary.length < size ){[ p, q] =[ q, p + q] ary.push( q ) yield}return ary}
function calcFibAryAsync( size ){returnnew Promise( resolve =>{const step = calcFibAryStep( size )const proceed = deadline =>{do{const{ value, done} = step.next()if ( done ) resolve( value )}while ( deadline.timeRemaining() > 0 ) requestIdleCallback( proceed )} requestIdleCallback( proceed )} )}calcFibAryAsync( 1e7 ).then( a => console.log( a ) )
効率よくシンプルで美しく書くのが難しい。
async関数とrequestIdleCallbackを使うと:
asyncfunction calcFibAryAsync( size ){let p = 1, q = 1const ary =[ p, q]const waitUntilIdle = () =>new Promise( ok => requestIdleCallback( ok ) )let deadline = await waitUntilIdle()while ( ary.length < size ){[ p, q] =[ q, p + q] ary.push( q )if ( deadline.timeRemaining() == 0 ) deadline = await waitUntilIdle()}return ary}calcFibAryAsync( 1e7 ).then( a => console.log( a ) )
固まらず、スマートに書ける。
V85.2.328
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。