Возвращение обещанного массива - PullRequest
2 голосов
/ 09 июня 2019

У меня есть следующий объект, хранящийся в переменной ($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()) что:

  1. Проходит через каждый из этих ключей и отправляет их в другую функцию ($._urlExists()), которая проверяет, является ли URL действительным / отзывчивым,

  2. Если true, $._findService() создает новый массив только с ключом и его элементами,

  3. И должен возвращать этот новый массив.

К сожалению, у меня проблемы с третьим шагом - возвращением нового массива.

У меня есть Google, и я прочитал столько, сколько смогу о Обещаниях , .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 ]

1 голос
/ 09 июня 2019

Ваша проблема заключалась в том, что вы ничего не возвращали в области действия функции, и вы должны были вернуть обещание (я).

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 */ })

Примечание: когда вы возвращаете что-то из асинхронной функции, вы получаете обещание, поэтому, когда вы используете ожидание, вы ожидаете ожидаемого результата обещания.

Нети никогда не будет недостатком в использовании асинхронности и ожидания по сравнению с Promise, и это современно и лучше, поскольку вы не создаете больше вложенных функций, используя синтаксис «then» или «new Promise».

0 голосов
/ 09 июня 2019

Я бы порекомендовал небольшое изменение на 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 в этой программе не дает никаких преимуществ

...