如题
在文章 json 里的value 如何从不同的上下文中取值 中介绍了从静态数据源里获取json。
怎么从 api 获取呢,这样就将数据源扩展到任何数据了。
从api 获取,其实是异步获取,这里要用到promise
实现
改动的代码不多,把两个方法 promise 化就可以实现
第一方法 replaceParams
原方法为
function replaceParams(params, current_data_source) {
if (test.is_array(params)) {
params = params.map(param=>replaceParams(param, current_data_source))
}
else if (test.is_object(params)) {
if (params._data_source) {
params = replaceParams(params.key, getDataSource(params))
} else {
if (test.is_array(current_data_source)) {
params = current_data_source.map(item=> replaceParams(JSON.parse(JSON.stringify(params)), item))
} else {
Object.keys(params).map(key => params[key]=replaceParams(params[key], current_data_source))
}
}
}
else if (test.is_string(params)) {
params = replaceParam(params, current_data_source)
}
return params
}
async后为
async function replaceParams(params, current_data_source) {
if (test.is_function(current_data_source)) {
do {
current_data_source = await current_data_source()
} while (test.is_function(current_data_source))
// 看下是否是动态数据源
if (test.is_object(current_data_source) && current_data_source._is_dynamic) {
current_data_source = await replaceParams(current_data_source.data || [])
}
}
if (test.is_array(params)) {
params = await Promise.all(params.map(async param => await replaceParams(param, current_data_source)))
}
else if (test.is_object(params)) {
if (params._data_source) {
params = await replaceParams(params.key, getDataSource(params))
} else {
if (test.is_array(current_data_source)) {
params = await Promise.all(current_data_source.map(async item => await replaceParams(JSON.parse(JSON.stringify(params)), item)))
} else {
await Promise.all(Object.keys(params).map(async key => params[key] = await replaceParams(params[key], current_data_source)))
}
}
}
else if (test.is_string(params)) {
params = await replaceParam(params, current_data_source)
}
return params
}
函数内添加了几行
if (test.is_function(current_data_source)) {
do {
current_data_source = await current_data_source()
} while (test.is_function(current_data_source))
// 看下是否是动态数据源
if (test.is_object(current_data_source) && current_data_source._is_dynamic) {
current_data_source = await replaceParams(current_data_source.data || [])
}
}
预先把数据源获取出来,假如数据源是一个动态数据源(即数据源里面也是从其他地方获取的)
第二个方法 replaceParam
原方法
function replaceParam(param, obj) {
if (!test.is_string(param)) {
return param
}
if (param.indexOf(':') < 0) {
return param;
}
if (param.startsWith(':')) {
console.log('replaceParam', param, '->', data_get(obj, param.slice(1)))
return data_get(obj, param.slice(1));
}
return param.replace(/:([\w\.]+)/g, function (match, key) {
console.log('replaceParam', ':'+key, '->', data_get(obj, key))
return data_get(obj, key);
});
}
async 后为
async function replaceParam(param, obj) {
if (!test.is_string(param)) {
return param
}
if (param.indexOf(':') < 0) {
return param;
}
if (typeof obj === 'function') {
obj = await obj()
}
if (param.startsWith(':')) {
console.log('replaceParam', param, '->', data_get(obj, param.slice(1)))
return data_get(obj, param.slice(1));
}
return param.replace(/:([\w\.]+)/g, function (match, key) {
console.log('replaceParam', ':' + key, '->', data_get(obj, key))
return data_get(obj, key);
});
}
代码里多了三行,主要是为了适配数据源是一个函数,这个函数,可以直接返回对象,也可以返回一个promise,上方预先把函数拦截掉了,这个不要也可以。但作为一个独立的方法,实现它更灵活一点(注意,只支持一层函数)
if (typeof obj === 'function') {
obj = await obj()
}
所有代码为
var user = {
id: 1
}
var book = {
id: 2
}
var address = {
id: 3
}
var data_sources = {}
data_sources.user = user
data_sources.book = book
data_sources.address = address
function getDataSource(config) {
return data_sources[config._data_source] || data_sources
}
var test = {
is_array: function (value) {
if (typeof Array.isArray === 'function') {
return Array.isArray(value)
}
return Object.prototype.toString.call(value) === '[object Array]'
},
is_object: function (value) {
return Object.prototype.toString.call(value) === '[object Object]'
},
is_string: function (value) {
return typeof value === 'string'
},
is_function: function (value) {
return typeof value === 'function'
}
}
async function replaceParams(params, current_data_source) {
if (test.is_function(current_data_source)) {
do {
current_data_source = await current_data_source()
} while (test.is_function(current_data_source))
// 看下是否是动态数据源
if (test.is_object(current_data_source) && current_data_source._is_dynamic) {
current_data_source = await replaceParams(current_data_source.data || [])
}
}
if (test.is_array(params)) {
params = await Promise.all(params.map(async param => await replaceParams(param, current_data_source)))
}
else if (test.is_object(params)) {
if (params._data_source) {
params = await replaceParams(params.key, getDataSource(params))
} else {
if (test.is_array(current_data_source)) {
params = await Promise.all(current_data_source.map(async item => await replaceParams(JSON.parse(JSON.stringify(params)), item)))
} else {
await Promise.all(Object.keys(params).map(async key => params[key] = await replaceParams(params[key], current_data_source)))
}
}
}
else if (test.is_string(params)) {
params = await replaceParam(params, current_data_source)
}
return params
}
async function replaceParam(param, obj) {
if (!test.is_string(param)) {
return param
}
if (param.indexOf(':') < 0) {
return param;
}
if (typeof obj === 'function') {
obj = await obj()
}
if (param.startsWith(':')) {
console.log('replaceParam', param, '->', data_get(obj, param.slice(1)))
return data_get(obj, param.slice(1));
}
return param.replace(/:([\w\.]+)/g, function (match, key) {
console.log('replaceParam', ':' + key, '->', data_get(obj, key))
return data_get(obj, key);
});
}
function data_get(target, path, fallback) {
let segments = Array.isArray(path) ? path : path.split('.');
let [segment] = segments;
let find = target;
if (segment !== '*' && segments.length > 0) {
if (find[segment] === null || typeof find[segment] === 'undefined') {
find = typeof fallback === 'function' ? fallback() : fallback;
}
else {
find = data_get(find[segment], segments.slice(1), fallback);
}
}
else if (segment === '*') {
const partial = segments.slice(path.indexOf('*') + 1, path.length);
if (typeof find === 'object') {
find = Object.keys(find).reduce((build, property) => ({
...build,
[property]: data_get(find[property], partial, fallback)
}),
{});
}
else {
find = data_get(find, partial, fallback);
}
}
/*-----------------------------------------------------------------------------
| Arrayable Requirements
*-----------------------------------------------------------------------------
|
| . All arrays are converted to objects
| . For Example
| #Code
| Code -> data_set({ list: ['one', 'two', 'three'], 'list.*', 'update', true });
|
| #Input
| Input -> { list: ['one', 'two', 'three'] }
|
| #During We Convert Arrays To "Indexed Objects"
| During -> { list: { '1': 'one', '2': 'two', '3': 'three' } }
|
| #Before Output we convert "Indexed Objects" Back To Arrays
| From -> { list: { '1': 'update', '2': 'update', '3': 'update' } }
| Into -> { list: ['update', 'update', 'update'] }
|
| . Arrays convert into "Indexed Objects", allowing for wildcard (*) capabilities
| . "Indexed Objects" are converted back into arrays before returning the updated target
|
*/
if (typeof find === 'object') {
if (Object.prototype.toString.call(find) === '[object Array]') {
if (find.length == 0) {
return find
}
}
if (Object.keys(find).length > 0) {
const isArrayTransformable = Object.keys(find).every(index => index.match(/^(0|[1-9][0-9]*)$/));
return isArrayTransformable ? Object.values(find) : find;
}
} else {
return find;
}
};
验证
data_sources.users = [
{
id: 1,
name: "11"
},
{
id: 2,
name: "22"
}
]
data_sources.post = {
id: 4,
comment: {
id: 5
}
}
data_sources.promise = function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
id: 6
})
}, 5000)
})
}
data_sources.promise1 = function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
id: 7
})
}, 2000)
})
}
replaceParams({
'promise_id': {
"_data_source": "promise",
"key": {
"id": ":id"
}
},
'promise1_id': {
"_data_source": "promise1",
"key": {
"id": ":id"
}
},
'test': [
":user.id",
":book.id",
[
":user.id",
":book.id",
":address"
]
],
"users": ":users",
"_map_users": {
"_data_source": "users",
"key": {
"name": ":name"
}
},
"user_ids": ":users.*.id",
"extra": {
"user_ids": ":users.*.id",
"_user_ids": {
"_data_source": "users",
"key": ":*.id"
},
"post": {
"_data_source": "post",
"key": {
"post_id": ":id",
"comment": ":comment",
"comment_id": ":comment.id",
"_user_ids": {
"_data_source": "users",
"key": ":*.id"
}
}
}
}
}, data_sources).then(params=>console.log(JSON.stringify(params))).catch(error=>{console.log(error)})
// 5秒后 ouput {"promise_id":{"id":6},"promise1_id":{"id":7},"test":[1,2,[1,2,{"id":3}]],"users":[{"id":1,"name":"11"},{"id":2,"name":"22"}],"_map_users":[{},{}],"user_ids":[1,2],"extra":{"user_ids":[1,2],"_user_ids":[1,2],"post":{"post_id":4,"comment":{"id":5},"comment_id":5,"_user_ids":[1,2]}}}