◆ コールバックタイプの非同期関数を await できるようにする

Chrome 55 から async/await が使えるようになりました
Chromodo はいまだに 52 なので使えないですけど……


便利なのですが setTimeout や chrome 拡張機能の API などコールバックばかりで Promise 化していなくて 使いづらいところが多いです

最初はひとつひとつ Promise 化する関数作っていたのですが 似たようなものばかりだったので async 化する機能つくればよさそうと思って作ってみました
Function.prototype.async = function(pos){
return (...args) =>
new Promise((resolve, reject) => {
var iidx = Object.is(-0, pos) ? args.length : pos
var cb = (...cbarr) => resolve(cbarr)
args.splice(iidx, 0, cb)
this(...args)
})
}

Function.prototype.lasync = function(...args){
return this.async(0)(...args)
}

Function.prototype.rasync = function(...args){
return this.async(-0)(...args)
}

Gist

使い方

関数に async メソッドが増えているので async 化したいときに使います
引数にコールバック関数の位置を指定すると そこに自動で Promise の resolve 関数がセットされる仕組みです
!async function(){
console.log(new Date())
await setTimeout.async(0)(2000)
console.log(new Date())
}()

こうすると 現在時刻を表示して 2 秒まってから また現在時刻を表示します

一度関数を返して二回呼び出しするのは
const setTimeoutAsync = setTimeout.async(0)

として別の関数にしておくこともできるようにです


次に callback が最後にある版の wait 関数を作ってみます
function wait(msec, cb){
setTimeout(cb, msec)
}

wait(2000, () => console.log(1))

2 秒後に 1 と表示されます


これを async 化します
!async function(){
console.log(new Date())
await wait.async(-0)(2000)
console.log(new Date())
}()

コールバックの位置指定はマイナスを指定すれば後ろからカウントします
最後なら -0 でおっけいです


場所指定できて コールバックがどこに来てもいいようになっていますが 実際の関数ってコールバック関数の位置は基本最初か最後で ほとんどが最後ですよね

なので 最初と最後にコールバックが来るものを簡単に async 化できるように lasync と rasync メソッドもあります
!async function(){
console.log(new Date())
await setTimeout.lasync(2000)
console.log(new Date())
}()

!async function(){
console.log(new Date())
await wait.rasync(2000)
console.log(new Date())
}()


これで非同期生活が快適になる……はずです