waitFun.mjs

import get from 'lodash-es/get.js'
import genPm from './genPm.mjs'
import isfun from './isfun.mjs'
import ispint from './ispint.mjs'
import ispm from './ispm.mjs'


/**
 * 等待f函數回傳true
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/waitFun.test.mjs Github}
 * @memberOf wsemi
 * @param {Function} fun 輸入判斷用函數
 * @param {Object} opt 輸入設定物件,預設{}
 * @param {Integer} [opt.attemptNum=200] 輸入最大嘗試次數,為正整數,預設200
 * @param {Integer} [opt.timeInterval=1000] 輸入嘗試時間週期,為正整數,單位為ms,預設1000
 * @returns {Promise} 回傳Promise,resolve為空代表f函數回傳true或超過最大嘗試次數,reject為錯誤訊息
 * @example
 *
 * async function topAsync() {
 *
 *     function test1() {
 *         return new Promise((resolve, reject) => {
 *             let ms = []
 *
 *             let i = 0
 *             waitFun(function() {
 *                 i++
 *                 console.log('waiting: ' + i)
 *                 ms.push('waiting: ' + i)
 *                 return i >= 2
 *             })
 *                 .then(function() {
 *                     console.log('test1 then')
 *                     ms.push('test1 then')
 *                 })
 *
 *             setTimeout(function() {
 *                 resolve(ms)
 *             }, 1100)
 *
 *         })
 *     }
 *     console.log('test1')
 *     let r1 = await test1()
 *     console.log(JSON.stringify(r1))
 *     // test1
 *     // waiting: 1
 *     // waiting: 2
 *     // test1 then
 *     // ["waiting: 1","waiting: 2","test1 then"]
 *
 *     function test2() {
 *         let ms = []
 *         let i = 0
 *
 *         let f = () => {
 *             return new Promise((resolve, reject) => {
 *                 setTimeout(function() {
 *                     i++
 *                     console.log('waiting: ' + i)
 *                     ms.push('waiting: ' + i)
 *                     resolve(i >= 2)
 *                 }, 1100)
 *             })
 *         }
 *
 *         return waitFun(f)
 *             .then(function() {
 *                 console.log('test2 then')
 *                 ms.push('test2 then')
 *                 return ms
 *             })
 *
 *     }
 *     console.log('test2')
 *     let r2 = await test2()
 *     console.log(JSON.stringify(r2))
 *     // test2
 *     // waiting: 1
 *     // waiting: 2
 *     // test2 then
 *     // ["waiting: 1","waiting: 2","test2 then"]
 *     // waiting: 3
 *
 * }
 * topAsync().catch(() => {})
 *
 */
async function waitFun(fun, opt = {}) {
    let r = null

    //pm
    let pm = genPm()

    //check
    if (!isfun(fun)) {
        pm.reject('waitfunction需輸入函數f')
        return pm
    }

    //func
    let func = async () => {
        let r = fun()
        if (ispm(r)) {
            r = await r
        }
        return r
    }

    //immediate call
    r = await func()
    if (r === true) {
        pm.resolve()
        return pm
    }

    //attemptNum
    let attemptNum = get(opt, 'attemptNum', null)
    if (!ispint(attemptNum)) {
        attemptNum = 200
    }

    //timeInterval
    let timeInterval = get(opt, 'timeInterval', null)
    if (!ispint(timeInterval)) {
        timeInterval = 1000
    }

    //setInterval
    let n = 0
    let t = setInterval(async() => {
        n += 1
        //console.log('waitFun: ', n)

        r = await func()
        if (r === true) {
            //console.log('resolve', n)
            clearInterval(t)
            pm.resolve()
        }
        if (n > attemptNum) {
            //console.log('reject', n, attemptNum)
            clearInterval(t)
            pm.reject(`exceeded attemptNum[${attemptNum}]`) //已超過最大次數
        }

    }, timeInterval)

    return pm
}


export default waitFun