import kotlin.js.Promise
import kotlin.browser.*
fun main() {
lateinit var resolve: (Int)->Unit
val promise = Promise
resolve = Yes
}
promise.then { result -> // only execute when promise fullfill
println("I got $result")
}
window.setTimeout( {resolve(0)}, 2000) // resolve result sometime or somewhere
}
例如應用在按鍵事件驅動的不定時的異步化(async function)程式上相當實用.
promise 的原理很簡單, 只要沒呼叫 resolve( ) 去解析, 就會維持在暫停(suspend)狀態, 一旦執行過 resolve( ) 後就變成滿足(fullfill)狀態. 後續當呼叫 then { } 區塊時, 若還是在暫停狀態下,沒意外(exception)的話,就維持該狀態,但要將該區塊(指標變數)附加(累積)到 promise 物件裏面,一旦呼叫了 resolve(result), resolve 除了會解析結果外, 同時還會就將結果傳遞給之前所累積的 then { } 區塊去執行. 也就是說只有在滿足狀態當下, promise 的 then { } 區塊才會執行. 有個應用情境是:將 promise.then { } 區塊放在函式內執行, 再用像是 window.setTimeout 或是 window.window.requestAnimationFrame 定時啟動該函式, 重複啟動函式時, 若 promise 一直維持在暫停的狀態, 就會造成 then 區塊不停的累積, 一旦狀態滿足時, 就有可能造成區塊重複執行的後遺症, 例如:
import kotlin.js.Promise
import kotlin.browser.*
fun main() {
lateinit var resolve: (Int)->Unit
val promise = Promise < Int > { Yes, _ ->
resolve = Yes
}
var count = 0
fun render( ) {
val capture = count
promise.then { result -> // dupcate then if not fullfill
println("fullfill: result=${result} capture=${capture}")
}
if( count ++ < 10 ) window.requestAnimationFrame( {render() } )
}
window.requestAnimationFrame({render() })
// promise not resolve
window.setTimeout( {resolve(0)}, 2000) // resolve result sometime or somewhere
}
執行結果:
fullfill: result=0 capture=0
fullfill: result=0 capture=1
fullfill: result=0 capture=2
fullfill: result=0 capture=3
fullfill: result=0 capture=4
fullfill: result=0 capture=5
fullfill: result=0 capture=6
fullfill: result=0 capture=7
fullfill: result=0 capture=8
fullfill: result=0 capture=9
fullfill: result=0 capture=10
為了用 kotlin 實現 async/await 的邏輯. 運用 promise 物件, 基本上就可以成為 async function, await 只能放在 async function 裏面, 直到 promise 完成解析(滿足狀態)才能進行後續動作, 因此特別用高階函式及 skip re-entry 技巧, 將 promise 包進新的類型, 並把他的 then 區塊打包放進高階函式當成 callback 函式去執行, 就能解決重複執行的困擾:
import kotlin.js.Promise
import kotlin.browser.*
class myAsync {
var once = 0
lateinit var resolve:(Int)-> Unit
val promise = Promise < Int > { Yes, _ ->
resolve = Yes
}
fun bwait(callback: (Int) -> Unit ) { // high order function with callback function
promise.then { result ->
if (once ++ == 0) callback(result ) // 只執行第一次的 then 區塊
}
}
fun await(callback: (Int) -> Unit ) { // high order function with callback function
once ++
promise.then { result ->
if (-- once == 0) callback(result ) // 只執行最後一次的 then 區塊
}
}
}
fun main() {
val async = myAsync( )
var count = 0
fun render( ) {
val capture = count
async.await { result -> // no duplicate then if fullfill
println("fullfill: result=${result} capture=${capture}")
}
if( count ++ < 10 ) window.requestAnimationFrame( {render() } )
}
window.requestAnimationFrame( { render() } )
window.setTimeout( {async.resolve(0)}, 2000) // resolve result sometime or somewhere
}
若是用 async.await 等待執行的結果:
fullfill: result=0 capture=10
若是用 async.bwait 等待執行的結果:
fullfill: result=0 capture=0
沒有留言:
張貼留言