Возвращение обещанного массива
У меня есть следующий объект, хранящийся в переменной ($gameSystem._ipLookupJSON
):
{
"www.geoplugin.net/json.gp?jsoncallback=?": {
"IP": "geoplugin_request",
"Country": "geoplugin_countryCode",
"City": "geoplugin_city"
},
"gd.geobytes.com/GetCityDetails?callback=?": {
"IP": "geobytesipaddress",
"Country": "geobytescountry",
"City": "geobytescity"
},
"ip-api.com/json": {
"IP": "ip",
"Country": "country_name",
"City": "city"
},
"ipinfo.io/json": {
"IP": "ip",
"Country": "country",
"City": "city"
}
}
Каждый из ключей в этом объекте является URL.
У меня есть функция ($._findService()
) это:
Проходит через каждый из этих ключей и отправляет их в другую функцию (
$._urlExists()
), который проверяет, является ли URL действительным / отзывчивым,Если правда,
$._findService()
создает новый массив только с ключом и его элементами,- И должен вернуть этот новый массив.
К сожалению, у меня проблемы с третьим шагом - возвращением нового массива.
У меня есть Google, и я читаю как можно больше об Promises, .then и Async / Await, но я просто не могу понять это, и в конце я просто смотрю на эти строки кода.
const isServiceAvailable = async url_to_check => {
console.log(url_to_check);
return await subaybay.an._urlExists("http://" + url_to_check);
};
const checkServices = async(json_data) => {
return await Promise.all(Object.keys(json_data).map(url_to_check => isServiceAvailable(url_to_check)));
};
$._findService = function(json_data) {
var url_check = checkServices(json_data);
url_check.then(function(values) {
for (i = 0; i < values.length; i++) {
if (values[i] === true) {
var service_to_use = new Promise(function(resolve, reject) {
var result = [];
result.push(json_data[Object.keys(json_data)[i]]);
result.unshift(Object.keys(json_data)[i]);
resolve(result);
});
service_to_use.then(function(value) {
console.log(value);
return value;
});
};
};
});
};
Я надеюсь на $._findService()
вернуть массив.
Но, увы, все, что я получаю, это undefined
,
Я прошу прощения, если мой код не изящен или симпатичен - я только учу себя JavaScript с конца февраля.
2 ответа
Ваша проблема заключалась в том, что вы ничего не возвращали в области действия функции, и вы должны были вернуть обещание (я).
const isServiceAvailable = url_to_check => subaybay.an._urlExists("http://" + url_to_check);
const checkServices = urls => Promise.all(urls.map(url_to_check => {
return {url: url_to_check,status: isServiceAvailable(url_to_check)}
}));
$._findService = async function(json_data) {
const values = await checkServices(Object.keys(json_data));
return values.filter(v => v.status).map(v => v.url);
};
Затем вы можете использовать:
const result = await $._findService(json_data)
или же
$._findService(json_data).then(result => { /* Do something */ })
Примечание: когда вы возвращаете что-то из асинхронной функции, вы получаете обещание, поэтому, когда вы используете await, вы ожидаете ожидаемого результата обещания.
Нет и никогда не будет никаких недостатков в использовании асинхронности и ожидания по сравнению с Promise, и это современно и лучше, так как вы не создаете больше вложенных функций, используя синтаксис "then" или "new Promise".
Я бы порекомендовал небольшое изменение checkServices
, В настоящее время тип ввода - это объект, а вывод - обещание массива. Я думаю, что было бы более интуитивно понятно вернуть обещание объекта, соответствующее исходному вводу -
// old function
checkServices({ "/foo": ..., "bar": ... })
// => Promise [ true, false ]
// new function
checkServices({ "/foo": ..., "bar": ... })
// => Promise { "/foo": true, "/bar": false }
Вот изменения -
// old function
const checkServices = async(json_data) => {
return await Promise.all(Object.keys(json_data).map(url_to_check => isServiceAvailable(url_to_check)));
};
// new function
const checkServices = (o = {}) =>
Promise.all(
Object.keys(o).map(k =>
isServiceAvailable(k).then(v => [ k, v ])
)
)
.then(Object.fromEntries)
С этим результатом легко найти все true
ключи для объекта -
$._findService = (o = {}) =>
checkServices(o).then(o =>
Object.keys(o).filter(k => o[k])
)
$._findService({ "/foo": ..., "bar": ... })
// Promise [ "/foo" ]
Разверните фрагмент ниже, чтобы запустить эту программу в своем браузере -
const checkServices = (o = {}) =>
Promise.all(
Object.keys(o).map(k =>
isServiceAvailable(k).then(v => [ k, v ])
)
)
.then(Object.fromEntries)
// fake implementation for demo
const isServiceAvailable = (service = "") =>
new Promise (r =>
setTimeout (r, 1000, service === "/foo")
)
_findService = (o = {}) =>
checkServices(o).then(o =>
Object.keys(o).filter(k => o[k])
)
checkServices({ "/foo": 1, "/bar": 2 }).then(console.log, console.error)
// { "/foo": true, "/bar": false }
_findService({ "/foo": 1, "/bar": 2 }).then(console.log, console.error)
// [ "/foo" ]
Там нет никакого преимущества использования async-await
в этой программе