Я делаю несколько обращений к серверу и создаю страницы и сообщения в формате yaml из API в моем gulpfile. Функции кажутся достаточно похожими, чтобы я мог сделать одну функцию для всех.
Я зацикливаюсь на создании объекта для каждого элемента, поскольку jsonObj не может быть определен вне XMLHttpRequest.
Вот мой код:
function collectLoop(slug, tempDir, destDir, args) {
const newObject = args;
fs.writeFile(`${tempDir}${slug}.json`,
JSON.stringify(newObject), function (err) {
if (err) throw err;
});
gulp.src(`${tempDir}${slug}.json`)
.pipe(jsonToYaml({ safe: true}))
.pipe(gulp.dest(destDir));
};
/*********************************************************************/
/******************************* PAGES *******************************/
/*********************************************************************/
function pageCollection(url, tempDir, destDir) {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
const jsonObj = JSON.parse(xhr.responseText);
checkDir(tempDir);
checkDir(destDir);
for (let i = 0; i < jsonObj.length; i += 1) {
let hero_heading = false;
let hero_subheading = false;
if (jsonObj[i].acf.hero != undefined) {
hero_heading = jsonObj[i].acf.hero.heading;
hero_subheading = jsonObj[i].acf.hero.subheading;
}
collectLoop(jsonObj[i].slug, tempDir, destDir, {
"obj_id" : jsonObj[i].id,
"title" : jsonObj[i].title.rendered,
"slug" : jsonObj[i].slug,
"modified" : jsonObj[i].modified,
"featured_image" : {
"large" : jsonObj[i]._embedded['wp:featuredmedia'][0].source_url,
"small" : jsonObj[i]._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url,
},
"settings" : {
"contact_box" : jsonObj[i].acf.contact_box,
"footer_map" : jsonObj[i].acf.map,
"hero_banner" : jsonObj[i].acf.hero_banner,
},
"hero" : {
"heading" : hero_heading,
"subheading" : hero_subheading,
},
"contact_form" : jsonObj[i].acf.contact_form,
"excerpt" : jsonObj[i].acf.excerpt,
"content" : jsonObj[i].content.rendered,
});
}
}
};
xhr.open('GET', url);
xhr.send();
}
/*********************************************************************/
/******************************* POSTS *******************************/
/*********************************************************************/
function postCollection(url, tempDir, destDir) {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
const jsonObj = JSON.parse(xhr.responseText);
checkDir(tempDir);
checkDir(destDir);
for (let i = 0; i < jsonObj.length; i += 1) {
collectLoop(jsonObj[i].slug, tempDir, destDir, {
"obj_id" : jsonObj[i].id,
"title" : jsonObj[i].title.rendered,
"slug" : jsonObj[i].slug,
"date" : jsonObj[i].date,
"modified" : jsonObj[i].modified,
"featured_image" : {
"large" : jsonObj[i]._embedded['wp:featuredmedia'][0].source_url,
"small" : jsonObj[i]._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url,
},
"excerpt" : jsonObj[i].excerpt.rendered,
"content" : jsonObj[i].content.rendered,
});
}
}
};
xhr.open('GET', url);
xhr.send();
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Возможно, это следует разместить в https://codereview.stackexchange.com, а не в stackoverflow. Но я все равно попробую на это ответить
Вы можете создать Функции, возвращающие функцию
Вот, наверное, что бы я сделал.
fetch вместо XMLHttpRequestasync/await, чтобы избежать ада обратного вызоваfor..of, чтобы постоянно избегать jsonObj[i]Object.assign, чтобы взять объект по умолчанию, который вы делаете во всех запросах, и использовать объект, возвращаемый сопоставлением fn(PS: не проверено)
function collectLoop(slug, tempDir, destDir, args) {
const newObject = args
const file = `${tempDir}${slug}.json`
fs.writeFile(file, JSON.stringify(newObject), err => {
if (err) throw err
})
gulp.src(file)
.pipe(jsonToYaml({ safe: true }))
.pipe(gulp.dest(destDir))
}
// Get is a function that returns another function
const get = (() => {
async function get (map, url, tempDir, destDir) {
const res = await fetch(url)
const jsonObj = await res.json()
checkDir(tempDir)
checkDir(destDir)
for (let item of jsonObj) {
// Default for everything
collectLoop(item.slug, tempDir, destDir, Object.assign({
obj_id: item.id,
title: item.title.rendered,
slug: item.slug,
date: item.date,
modified: item.modified,
featured_image: {
large: item._embedded['wp:featuredmedia'][0].source_url,
small: item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url,
},
excerpt: item.excerpt.rendered,
content: item.content.rendered
}, map(jsonObj)))
}
}
return (map = () => {}) => (...args) => get(map, ...args)
})()
const postCollection = get() // no mapping needed, dose the default
const pageCollection = get(item => ({ // This is our mapping fn
settings: {
contact_box: item.acf.contact_box,
footer_map: item.acf.map,
hero_banner: item.acf.hero_banner,
},
hero: {
heading: item.acf.hero ? item.acf.hero.heading : false,
subheading: item.acf.hero ? item.acf.hero.subheading : false
},
contact_form: item.acf.contact_form
}))
Добро пожаловать на SO! Вы когда-нибудь пытались объединить эти две функции? Вы где-то застряли?