ES 2017 async/await関数を使用する注意点
4022 ワード
node 7.6.0正式にasync/await関数を実装するにつれて、jsの非同期プログラムは以前よりもっと簡単になります.しかし、私たちはasync/awaitを全面的に抱え込む前に、この特性について詳しく知る必要があります.
書き方
基本的に、どの関数も関数宣言 関数式 方法定義 矢印関数
戻り値がprmitive値であっても、
正常(Fulfill)
下記のコードを考慮します. に戻る. を実行するまで保留すると理解できる.
したがって、上のコード出力は
Promiseを混ぜたバージョンをもう一つ見てみましょう.
async関数とcalback
よくある間違い は ではありません.
正しい書き方は
上から見れば、
書き方
基本的に、どの関数も
async
関数になります.以下は合法的な書き方です.async function foo () {}
const foo = async function () {}
const obj = { async foo () {} }
async () => {}
async
関数は、常にPromise
に戻る.戻り値がprmitive値であっても、
async
関数はreturn
を介して自動的に戻り値をPromise
オブジェクトに包装して返します.したがって、次の2つの関数は等価である.正常(Fulfill)
// async
async function foo () {
return 'a'
}
// Promise
function foo () {
return Promise.resolve('a')
}
異常(Reject)// async
async function foo () {
throw new Error('error')
}
// Promise
function foo () {
return Promise.reject(new Error('error'))
}
なお、戻り値自体がPromise
オブジェクトである場合には、async
関数のreturn
は、戻り値を二回包装しない.await
は常に順番に実行される.async
関数を使用する前に、私たちはまたその動作メカニズムを解明しなければなりません.特に実行順序においては、完全に同期された思惟はasync
関数に適用されないかもしれない.下記のコードを考慮します.
function asyncGet (x) {
return new Promise(resolve => setTimeout(() => {
console.log('a')
resolve(x)
}, 500))
}
async function test () {
console.log('b')
const x = 3 + 5
console.log(x)
const a = await asyncGet(1)
console.log(a)
const b = await asyncGet(2)
console.log(b)
console.log('c')
return a + b
}
const now = Date.now()
console.log('d')
test().then(x => {
console.log(x)
console.log(`elapsed: ${Date.now() - now}`)
})
console.log('f')
async
関数は、一般関数と同じ順序で実行され、await
文が実行されると、Promise
オブジェクトawait
は、async
の関数を、待つPromise
がfulfillまたはrejectによって後でコードasync
関数の戻り値は、一般Promise
と区別されていません.したがって、上のコード出力は
d
b
8
f
a
1
a
2
c
3
elapsed: 1010
注意dとfの中間出力Promiseを混ぜたバージョンをもう一つ見てみましょう.
function asyncGet (x) {
return new Promise(resolve => setTimeout(() => {
console.log('a')
resolve(x)
}, 500))
}
async function test () {
console.log('b')
const x = 3 + 5
console.log(x)
const [a, b] = await Promise.all([
asyncGet(1),
asyncGet(2)
])
console.log('c')
return a + b
}
const now = Date.now()
console.log('d')
test().then(x => {
console.log(x)
console.log(`elapsed: ${Date.now() - now}`)
})
console.log('f')
出力結果d
b
8
f
a
a
c
3
elapsed: 509
elapsed
の違いに気づきましたか?これはなぜですか?await
はいつも順番に実行すると言います.異なるawaitの間では並行して実行できないので、本当の完全非同期はPromise.all
のような方法を借りなければなりません.async関数とcalback
await
は、直接的な小包の関数async
に影響を与えることができるだけである.したがって、calback関数のawait
は、async
関数全体の実行を保留しない.よくある間違い
async function getAll (vals) {
return vals.map(v => await asyncGet(v))
}
このコードには文法的なエラーがあり、await
はasync
関数の内部にありません.map
のcalbackにasync
を加えれば?async function getAll (vals) {
return vals.map(async v => await asyncGet(v))
}
このコードは実行できますが、まだ二つの問題があります.Promise
オブジェクトの配列を返します.期待されるvalue配列await
はmap
のcalbackを一時停止するだけですので、map
が完成した時には、asyncGet
も全部完成したとは保証できません.正しい書き方は
Promise.all
を借りなければなりません.async function getAll (vals) {
return Promise.all(vals.map(v => asyncGet(v)))
}
締め括りをつける上から見れば、
Promise
はasync
関数の基礎であり、async
関数を楽しく使用するには、Promise
についての比較的深い理解が必要である.いくつかの一般的なタスクも、async
関数だけでは実現できません.この文章を読んでから、async
の関数に対してもっと全面的な認識を持っていただきたいです.そうすれば、もっと使いやすくなります.