UNPKG

wsemi

Version:

A support package for web developer.

344 lines (330 loc) 12.3 kB
import get from 'lodash/get' import genPm from './genPm.mjs' import isfun from './isfun.mjs' import isnull from './isnull.mjs' import isundefined from './isundefined.mjs' /** * 掛勾非同步(Promise)函數,可監聽或修改Promise的輸出入訊號 * * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/pmHook.test.mjs Github} * @memberOf wsemi * @param {Function} fun 輸入非同步Promise函數 * @param {Function} [cb=() => {}] 輸入回調函數,預設()={},cb函數之輸入為監聽到的資訊物件,欄位有mode與data,mode可為'before'、'afterThen'、'afterCatch'字串,而data則代表非同步函數的輸入或輸出資訊。若想於cb函數修改回傳,則由cb函數的輸入修改完回傳即可。例如收到msg={mode:'before',data:'123'},將msg.data='abc',再return msg.data * @returns {Promise} 回傳為Promise,resolve為回傳成功結果,reject為回傳失敗訊息 * @example * * async function topAsync() { * * async function test1() { * return new Promise((resolve, reject) => { * let ms = [] * * //使用resolve * let pm = function (v1, v2) { * return new Promise(function(resolve, reject) { * ms.push(`resolve: v1=${v1}, v2=${v2}`) * resolve(`resolve: v1=${v1}, v2=${v2}`) * }) * } * * //針對before修改輸入 * let pmr = pmHook(pm, (msg) => { * console.log('cb', msg) * if (msg.mode === 'before') { * //arguments有兩個輸入故得分開改 * msg.data[0] = '[modify input a]' + msg.data[0] * msg.data[1] = '[modify input b]' + msg.data[1] * return msg.data * } * }) * * pmr('t1', 12.3) * .then(function(msg) { * console.log('t1 then', msg) * ms.push('t1 then: ' + msg) * }) * .catch(function(msg) { * console.log('t1 catch', msg) * ms.push('t1 catch: ' + msg) * }) * .finally(function() { * resolve(ms) * }) * * }) * } * console.log('test1') * let r1 = await test1() * console.log(JSON.stringify(r1)) * // test1 * // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } } * // cb { * // mode: 'afterThen', * // data: 'resolve: v1=[modify input a]t1, v2=[modify input b]12.3' * // } * // t1 then resolve: v1=[modify input a]t1, v2=[modify input b]12.3 * // ["resolve: v1=[modify input a]t1, v2=[modify input b]12.3","t1 then: resolve: v1=[modify input a]t1, v2=[modify input b]12.3"] * * async function test2() { * return new Promise((resolve, reject) => { * let ms = [] * * //使用resolve * let pm = function (v1, v2) { * return new Promise(function(resolve, reject) { * ms.push(`resolve: v1=${v1}, v2=${v2}`) * resolve(`resolve: v1=${v1}, v2=${v2}`) * }) * } * * //針對afterThen修改輸出 * let pmr = pmHook(pm, (msg) => { * console.log('cb', msg) * if (msg.mode === 'afterThen') { * //arguments有兩個輸入故得分開改 * msg.data = '[modify output]' + msg.data * return msg.data * } * }) * * pmr('t1', 12.3) * .then(function(msg) { * console.log('t1 then', msg) * ms.push('t1 then: ' + msg) * }) * .catch(function(msg) { * console.log('t1 catch', msg) * ms.push('t1 catch: ' + msg) * }) * .finally(function() { * resolve(ms) * }) * * }) * } * console.log('test2') * let r2 = await test2() * console.log(JSON.stringify(r2)) * // test2 * // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } } * // cb { mode: 'afterThen', data: 'resolve: v1=t1, v2=12.3' } * // t1 then [modify output]resolve: v1=t1, v2=12.3 * // ["resolve: v1=t1, v2=12.3","t1 then: [modify output]resolve: v1=t1, v2=12.3"] * * async function test3() { * return new Promise((resolve, reject) => { * let ms = [] * * //使用reject * let pm = function (v1, v2) { * return new Promise(function(resolve, reject) { * ms.push(`reject: v1=${v1}, v2=${v2}`) * reject(`reject: v1=${v1}, v2=${v2}`) * }) * } * * //針對afterThen修改輸出, 但因使用reject故改不到 * let pmr = pmHook(pm, (msg) => { * console.log('cb', msg) * if (msg.mode === 'afterThen') { * //arguments有兩個輸入故得分開改 * msg.data = '[modify output]' + msg.data * return msg.data * } * }) * * pmr('t1', 12.3) * .then(function(msg) { * console.log('t1 then', msg) * ms.push('t1 then: ' + msg) * }) * .catch(function(msg) { * console.log('t1 catch', msg) * ms.push('t1 catch: ' + msg) * }) * .finally(function() { * resolve(ms) * }) * * }) * } * console.log('test3') * let r3 = await test3() * console.log(JSON.stringify(r3)) * // test3 * // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } } * // cb { mode: 'afterCatch', data: 'reject: v1=t1, v2=12.3' } * // t1 catch reject: v1=t1, v2=12.3 * // ["reject: v1=t1, v2=12.3","t1 catch: reject: v1=t1, v2=12.3"] * * async function test4() { * return new Promise((resolve, reject) => { * let ms = [] * * //使用reject * let pm = function (v1, v2) { * return new Promise(function(resolve, reject) { * ms.push(`reject: v1=${v1}, v2=${v2}`) * reject(`reject: v1=${v1}, v2=${v2}`) * }) * } * * //針對afterCatch修改輸出 * let pmr = pmHook(pm, (msg) => { * console.log('cb', msg) * if (msg.mode === 'afterCatch') { * //arguments有兩個輸入故得分開改 * msg.data = '[modify output]' + msg.data * return msg.data * } * }) * * pmr('t1', 12.3) * .then(function(msg) { * console.log('t1 then', msg) * ms.push('t1 then: ' + msg) * }) * .catch(function(msg) { * console.log('t1 catch', msg) * ms.push('t1 catch: ' + msg) * }) * .finally(function() { * resolve(ms) * }) * * }) * } * console.log('test4') * let r4 = await test4() * console.log(JSON.stringify(r4)) * // test4 * // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } } * // cb { mode: 'afterCatch', data: 'reject: v1=t1, v2=12.3' } * // t1 catch [modify output]reject: v1=t1, v2=12.3 * // ["reject: v1=t1, v2=12.3","t1 catch: [modify output]reject: v1=t1, v2=12.3"] * * async function test5() { * return new Promise((resolve, reject) => { * let ms = [] * * //使用resolve, 此函數無輸入 * let pm = function () { * return new Promise(function(resolve, reject) { * ms.push(`resolve`) * resolve(`resolve`) * }) * } * * //針對afterThen修改輸出 * let pmr = pmHook(pm, (msg) => { * console.log('cb', msg) * if (msg.mode === 'afterThen') { * //arguments有兩個輸入故得分開改 * msg.data = '[modify output]' + msg.data * return msg.data * } * }) * * pmr() * .then(function(msg) { * console.log('t1 then', msg) * ms.push('t1 then: ' + msg) * }) * .catch(function(msg) { * console.log('t1 catch', msg) * ms.push('t1 catch: ' + msg) * }) * .finally(function() { * resolve(ms) * }) * * }) * } * console.log('test5') * let r5 = await test5() * console.log(JSON.stringify(r5)) * // test5 * // cb { mode: 'before', data: [Arguments] {} } * // cb { mode: 'afterThen', data: 'resolve' } * // t1 then [modify output]resolve * // ["resolve","t1 then: [modify output]resolve"] * * } * topAsync().catch(() => {}) * */ function pmHook(fun, cb = () => {}) { //check if (!isfun(fun)) { return null } if (!isfun(cb)) { cb = () => {} } function getData(newData, oriData) { let r if (!isnull(newData) && !isundefined(newData)) { r = get(newData, 'data', null) if (r) { return r //若回傳是包成原始物件格式, 則取出data才回傳 } return newData //若回傳是有效的新數據, 直接回傳 } return oriData //若回傳為無效數據, 則回傳原始數據 } return function() { let r //pm let pm = genPm() //callback before let input = cb({ mode: 'before', data: arguments, }) //check if (isnull(input) || isundefined(input)) { input = arguments } //call fun with input fun(...input) .then((output) => { r = cb({ mode: 'afterThen', data: output, }) output = getData(r, output) pm.resolve(output) }) .catch((output) => { r = cb({ mode: 'afterCatch', data: output, }) output = getData(r, output) pm.reject(output) }) // //pxy // let pxy = new Proxy(fun(input), { // get(target, prop, receiver) { // //console.log('target=', target, ', prop=', prop, ', receiver=', receiver) // let value = Reflect.get(...arguments) // target // .then((output) => { // cb({ // mode: 'afterThen', // data: output, // }) // }) // .catch((output) => { // cb({ // mode: 'afterCatch', // data: output, // }) // }) // return typeof value === 'function' ? value.bind(target) : value // } // }) return pm } } export default pmHook