LoginSignup
0
1

More than 1 year has passed since last update.

JavaScript の Promise 試してみた

Last updated at Posted at 2021-07-24

モダン JavaScript で実装するとき async/await を非同期処理を扱うために使用しますが、async/awaitの挙動を理解するためにも、まずはPromiseの挙動を確認してみます。

promise

Promiseとは:

Promise オブジェクトは非同期処理の最終的な完了処理 (もしくは失敗) およびその結果の値を表現します。

Promiseを返す関数を作成

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        console.log('promise')
    })
}

resolveAfter2Seconds()
console.log('==end==')

結果

# node async.js
starting slow promise
promise
==end==

2秒後に実行される関数をPromiseでラップする

function resolveAfter2Seconds() {
    console.log("starting promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}

resolveAfter2Seconds()
console.log('==end==')

結果. 実行結果が変わった。Promiseによって非同期に実行されている.

# node async.js
starting promise
==end==
2秒後に実行されます
#

thenメソッドを使用してresolveを受け取る

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}

resolveAfter2Seconds()
  .then(resolve => console.log(resolve))
console.log('==end==')

結果

# node async.js
starting promise
==end==
2秒後に実行されます
slow
#

1秒後に実行される関数をラップしたPromiseを追加する

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}

function resolveAfter1Second() {
  console.log("starting fast promise")
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast")
      console.log("1秒後に実行されます")
    }, 1000)
  })
}

resolveAfter2Seconds()
resolveAfter1Second()

console.log('==end==')

結果. 処理の実行順序にかかわらず非同期で実行されている.

# node async.js
starting slow promise
starting fast promise
==end==
1秒後に実行されます
2秒後に実行されます

Promise.all()を使用すると非同期処理を平行で処理し、すべての処理が終了するのを待ってから結果を実行できる

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}


function resolveAfter1Second() {
  console.log("starting fast promise")
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast")
      console.log("1秒後に実行されます")
    }, 1000)
  })
}

Promise.all([resolveAfter2Seconds(), resolveAfter1Second()])
  .then(([result1, result2]) => {
    console.log(result1)
    console.log(result2)
  })

console.log('==end==')

結果

# node async.js
starting slow promise
starting fast promise
==end==
1秒後に実行されます
2秒後に実行されます
slow
fast

直列実行, 逐次実行

reduceを使うことで直列的に実行できる

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}


function resolveAfter1Second() {
  console.log("starting fast promise")
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast")
      console.log("1秒後に実行されます")
    }, 1000)
  })
}

[resolveAfter2Seconds, resolveAfter1Second]
  .reduce((p, f) => p.then(f), Promise.resolve())
  .then(result3 => console.log(result3))

console.log('==end==')

結果

# node async.js
==end==
starting slow promise
2秒後に実行されます
starting fast promise
1秒後に実行されます
fast

async/awaitを使うと簡潔に書ける

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}


function resolveAfter1Second() {
  console.log("starting fast promise")
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast")
      console.log("1秒後に実行されます")
    }, 1000)
  })
}

async function sequentialStart() {
  const slow = await resolveAfter2Seconds()
  console.log(slow)

  const fast = await resolveAfter1Second()
  console.log(fast)
}

sequentialStart()
console.log('==end==')

結果

# node async.js
starting slow promise
==end==
2秒後に実行されます
slow
starting fast promise
1秒後に実行されます
fast

async と await

asyncPromiseを返す(返値は暗黙的にPromise.resolveでラップされている)

awaitは非同期関数の実行を一時停止してPromiseの解決を待つ. 非同期関数が一時停止している間も, 呼び出し側の関数は実行が続く.

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}

async function asyncCall() {
  console.log('calling')
  const result = await resolveAfter2Seconds()
  console.log(result)
}

asyncCall()
console.log('==end==')

結果

# node async.js
calling
starting slow promise
==end==
2秒後に実行されます
slow

awaitを使用しないとasync関数内の実行は続いく

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}

async function asyncCall() {
  console.log('calling')
  const result = resolveAfter2Seconds()
  console.log(result)
}

asyncCall()
console.log('==end==')

結果

# node async.js
calling
starting slow promise
Promise { <pending> }
==end==
2秒後に実行されます

async関数の戻り値を確認

async function asyncCall() {
  console.log('calling')
  return 'success'
}

console.log(asyncCall())
console.log('==end==')

結果

# node async.js
calling
Promise { 'success' }
==end==

Promiseで返ってくる。Promise.resolve()でラップされているのでthenメソッドで繋げると

async function asyncCall() {
  console.log('calling')
  return 'success'
}

asyncCall()
  .then(result => console.log(result))

console.log('==end==')

結果. async関数の戻り値を実行できる.

# node async.js
calling
==end==
success

並列で実行させる

Promise.allを使用して並列で実行させる

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}

function resolveAfter1Second() {
  console.log("starting fast promise")
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast")
      console.log("1秒後に実行されます")
    }, 1000)
  })
}

async function parallel() {
  await Promise.all([
    (async() => console.log(await resolveAfter2Seconds()))(),
    (async() => console.log(await resolveAfter1Second()))()
  ])

  console.log('parallel end')
}

結果

Promise.allを使用しているので, すべてのプロミスが解決されるまで次の処理が実行されていない.

# node async.js
starting slow promise
starting fast promise
==end==
1秒後に実行されます
fast
2秒後に実行されます
slow
parallel end

非同期関数を並列で実行させて返り値を受け取る

function resolveAfter2Seconds() {
    console.log("starting slow promise")
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("slow")
            console.log("2秒後に実行されます")
        }, 2000)
    })
}


function resolveAfter1Second() {
  console.log("starting fast promise")
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast")
      console.log("1秒後に実行されます")
    }, 1000)
  })
}

async function parallel() {
  const result = await Promise.all([
    resolveAfter2Seconds(), resolveAfter1Second()
  ])
    .then(([result1, result2]) => {
      return ('resolve : ' + result1 + result2)
      // return Promise.resolve('resolve : '  + result1 + result2) ← これでも可
      // return new Promise(resolve => {
      //   resolve('resolve : '  + result1 + result2)  ← これでも可
      // })
    })

  console.log('parallel end')
  return result
}

parallel()
  .then(result => console.log(result))


console.log('==end==')

結果

# node async.js
starting slow promise
starting fast promise
==end==
1秒後に実行されます
2秒後に実行されます
parallel end
resolve : slowfast

参考

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1