Как задержать такую ​​функцию? [Дубликат]

Для сценариев на стороне сервера нет PHP, но nodeJS ...

Облачные функции Google написаны на JavaScript и выполняются в runtime времени Node.js.

Mandrill также поддерживает узел JS и имеет API-интерфейс Webhooks API . Поэтому можно потребовать, чтобы модуль узла в этих «облачных функциях» и «веб-крючках» ... и затем отправлял с ними HTML-форму.

Там должно быть несколько HTTP облачных функций, определенных в Firebase Console, чтобы позволить им подписываться, отписываться и управлять своими подписками. Можно даже создать разметку HTML для входной формы с облачными функциями, а затем прикрепить ее. В качестве примера не проверены и не включены никакие гарантии:

const functions = require('firebase-functions');
const mandrill = require('mandrill-api/mandrill');
var client = new mandrill.Mandrill('YOUR_API_KEY');

/* TODO: add the user on Firebase, respond through the API */
exports.user_add = functions.https.onRequest((req, res) => {

});

/* TODO: change subscription settings on Firebase, respond through the API */
exports.user_edit = functions.https.onRequest((req, res) => {

});

/* TODO: remove the user on Firebase, respond through the API */
exports.user_remove = functions.https.onRequest((req, res) => {

});

/* optional: generate the HTML markup of the form, send HTTP response */
exports.markup = functions.https.onRequest((req, res) => {

});

Можно связать события Firebase Auth , чтобы сохранить две пользовательские базы данных в синхронной (это не требуемый для Mandrill, но требуемый для MailChimp - независимо от того, использует ли он оболочку PHP или nodeJS):

exports.on_user_create = functions.auth.user().onCreate(event => {
   const user = event.data;
});

exports.on_user_delete = functions.auth.user().onDelete(event => {
   const user = event.data;
});

Firebase on Websites объясняет это, в то время как есть локальная Эмулятор для функций облака.

83
задан Michiel van Oosterhout 4 August 2012 в 12:58
поделиться

6 ответов

Нет, другого способа не существует: если у вас много мест и вы хотите отображать их на карте, лучшим решением будет следующее:

  • выбрать широту + долготу, используя геокодер, когда создается местоположение
  • , сохраните их в своей базе данных вместе с адресом
  • и используйте сохраненную широту + долготу, когда вы хотите отобразить карту.

Это, конечно, учитывая, что у вас намного меньше создания / изменения местоположений, чем у вас есть консультации по местам.

Да, это означает, что вам нужно будет сделать бит больше работы при сохранении местоположений - но это также означает:

  • Вы сможете выполнить поиск по географическим координатам, т. е. « Мне нужен список точек, которые находятся рядом, где я 'm now "
  • Отображение карты будет намного быстрее Даже с более чем 20 точками на нем
  • О, а также (последнее, но не наименьший) : это будет работать ;-). Вы менее склонны преодолевать пределы вызовов геокодера X за N секунд. И вы с меньшей вероятностью попадете в пределы Y-запросов геокодера в день.
82
ответ дан Pascal MARTIN 18 August 2018 в 05:52
поделиться
  • 1
    Мне любопытно, как вы можете быть уверены, что результаты верны через некоторое время (скажем, месяц). Вы повторно запрашиваете их каждый раз в то время? – Chris 10 March 2010 в 19:02
  • 2
    Если адрес (который у вас уже есть в вашей БД - иначе вы не сможете геокодировать) не изменяется, вероятность довольно низкая, чтобы широта / долгота изменилась. И, конечно, каждый раз, когда адрес изменяется, вы должны повторно запросить геокодер, чтобы получить широту + долготу, соответствующую новому адресу. – Pascal MARTIN 10 March 2010 в 19:08
  • 3
    Я сохранил lat / long в БД и извлек его из БД через AJAX в качестве массива, но затем он должен снова перейти в цикл java-скрипта, более того, я получил 173 местоположения от БД. Теперь он показывает мне тот же статус OVER_QUERY_LIMIT. Пожалуйста посоветуй... – Prabhu M 6 July 2011 в 16:46

EDIT:

Забыл сказать, что это решение находится в чистом js, единственное, что вам нужно, это браузер, который поддерживает обещания https://developer.mozilla.org/it/docs / Web / JavaScript / Reference / Global_Objects / Promise


Для тех, кто все еще нуждается в этом, я написал свое собственное решение, которое объединяет обещания с таймаутами.

Код:

/*
    class: Geolocalizer
        - Handles location triangulation and calculations.
        -- Returns various prototypes to fetch position from strings or coords or dragons or whatever.
*/

var Geolocalizer = function () {
    this.queue          = [];     // queue handler..
    this.resolved       = [];
    this.geolocalizer = new google.maps.Geocoder();  
};

Geolocalizer.prototype = {
    /*
        @fn: Localize
        @scope: resolve single or multiple queued requests.
        @params: <array> needles
        @returns: <deferred> object
    */
    Localize: function ( needles ) {
        var that = this;
        // Enqueue the needles.
        for ( var i = 0; i < needles.length; i++ ) {
            this.queue.push(needles[i]);
        }
        // return a promise and resolve it after every element have been fetched (either with success or failure), then reset the queue.
        return new Promise (
            function (resolve, reject) {
                that.resolveQueueElements().then(function(resolved){
                  resolve(resolved);
                  that.queue    = [];
                  that.resolved = [];
                });
            }
        );
    },

    /*
        @fn: resolveQueueElements
        @scope: resolve queue elements.
        @returns: <deferred> object (promise)
    */

    resolveQueueElements: function (callback) {
        var that = this;
        return new Promise(
            function(resolve, reject) {
                // Loop the queue and resolve each element.
                // Prevent QUERY_LIMIT by delaying actions by one second.
                (function loopWithDelay(such, queue, i){
                    console.log("Attempting the resolution of " +queue[i-1]);
                    setTimeout(function(){
                        such.find(queue[i-1], function(res){
                           such.resolved.push(res); 
                        });
                        if (--i) {
                            loopWithDelay(such,queue,i);
                        }
                    }, 1000);
                })(that, that.queue, that.queue.length);

                // Check every second if the queue has been cleared.
                var it = setInterval(function(){
                    if (that.queue.length == that.resolved.length) {
                        resolve(that.resolved);
                        clearInterval(it);
                    }
                }, 1000);
            }
        );
    },

    /*
        @fn: find
        @scope: resolve an address from string
        @params: <string> s, <fn> Callback
    */
    find: function (s, callback) {
        this.geolocalizer.geocode({
            "address": s
        }, function(res, status){
           if (status == google.maps.GeocoderStatus.OK) {
               var r = {
                   originalString:  s,
                   lat: res[0].geometry.location.lat(),
                   lng: res[0].geometry.location.lng()
               };
               callback(r);
           }
            else {
                callback(undefined);
                console.log(status);
                console.log("could not locate " + s);
            }
        });
    }
};

Обратите внимание, что это просто часть большей библиотеки, которую я написал для обработки файлов карт Google, поэтому комментарии могут быть запутанными.

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

Пример:

var myAmazingGeo = new Geolocalizer();
var locations = ["Italy","California","Dragons are thugs...","China","Georgia"];
myAmazingGeo.Localize(locations).then(function(res){ 
   console.log(res); 
});

Выход консоли:

Attempting the resolution of Georgia
Attempting the resolution of China
Attempting the resolution of Dragons are thugs...
Attempting the resolution of California
ZERO_RESULTS
could not locate Dragons are thugs...
Attempting the resolution of Italy

Возвращенный объект:

Вся магическая ситуация происходит здесь:

(function loopWithDelay(such, queue, i){
                    console.log("Attempting the resolution of " +queue[i-1]);
                    setTimeout(function(){
                        such.find(queue[i-1], function(res){
                           such.resolved.push(res); 
                        });
                        if (--i) {
                            loopWithDelay(such,queue,i);
                    }
                }, 750);
            })(that, that.queue, that.queue.length);

В основном, он обрабатывает каждый элемент с задержкой в ​​750 миллисекунд между каждым из них, поэтому каждые 750 миллисекунд адрес контролируется.

Я провел несколько дополнительных тестов, и я узнал, что даже в 700 миллисекунд я иногда получал ошибку QUERY_LIMIT, а с 750 у меня вообще не было проблем.

В любом случае, не стесняйтесь редактировать 750, если вы считаете себя в безопасности обрабатывая более низкую задержку.

Надеюсь, это поможет кому-то в ближайшем будущем;)

1
ответ дан briosheje 18 August 2018 в 05:52
поделиться

Я столкнулся с той же проблемой, пытаясь геокодировать 140 адресов.

Моим обходным путем было добавление usleep (100000) для каждого цикла следующего запроса геокодирования. Если статус запроса OVER_QUERY_LIMIT, спящий режим увеличивается на 50000, и запрос повторяется и т. Д.

И причина, по которой все полученные данные (lat / long) хранятся в файле XML, чтобы не запускать запрос каждый раз, когда страница загружается.

2
ответ дан gray 18 August 2018 в 05:52
поделиться
  • 1
    Ваш ответ нечеткий, вы имеете в виду на стороне сервера или этот javascript, если он последний, usleep - это not функция и, следовательно, будет неправильной, если это первая, тогда я предлагаю вам исправьте свой ответ, чтобы явно указать, что это серверная сторона, чтобы избежать двусмысленности. – t0mm13b 22 April 2014 в 17:11

Я только что протестировал Google Geocoder и получил ту же проблему, что и у вас. Я заметил, что я получаю только статус OVER_QUERY_LIMIT один раз каждые 12 запросов. Поэтому я жду 1 секунду (это минимальная задержка ожидания). Это замедляет приложение, но меньше, чем ждать 1 секунду каждого запроса

info = getInfos(getLatLng(code)); //In here I call Google API
record(code, info);
generated++; 
if(generated%interval == 0) {
holdOn(delay); // Every x requests, I sleep for 1 second
}

С основной метод holdOn:

private void holdOn(long delay) {
        try {
            Thread.sleep(delay);
        } catch (InterruptedException ex) {
            // ignore
        }
    }

Надеюсь, что это поможет

0
ответ дан Hugues 18 August 2018 в 05:52
поделиться

На самом деле вам не нужно ждать полной секунды для каждого запроса. Я обнаружил, что, если я жду 200 миллисекунд между каждым запросом, я могу избежать ответа OVER_QUERY_LIMIT, и пользовательский интерфейс проходим. С помощью этого решения вы можете загрузить 20 элементов за 4 секунды.

$(items).each(function(i, item){

  setTimeout(function(){

    geoLocate("my address", function(myLatlng){
      ...
    });

  }, 200 * i);

}
19
ответ дан Mohammad Dehghan 18 August 2018 в 05:52
поделиться
  • 1
    но (200 * i) означает, что пауза между каждым запросом увеличивается. Итак, 3-й запрос - 600, затем 800 и т. Д. – oyatek 5 April 2013 в 09:16
  • 2
    просто удалите '* i' – Chris 2 September 2013 в 20:50
  • 3
    setTimeout выполнит его один раз. Поэтому, если я прав, (..., 200 * i) будет планировать каждый вызов, разделенный на 200 мс (по комментариям oyatek), чего хочет достичь gabeodessess. Текущий (..., 200) будет выполнять все из них одновременно через 200 мс. Или я чего-то не хватает? – lepe 10 July 2014 в 07:37
  • 4
    @lepe Это правильно. – katalin_2003 4 December 2014 в 16:01
  • 5
    @gabeodess Я пробовал ваше решение, но все равно получаю OVER_QUERY_LIMIT Fiddle – Prabs 11 September 2015 в 06:46

К сожалению, это ограничение службы карт Google.

В настоящее время я работаю над приложением, использующим функцию геокодирования, и я сохраняю каждый уникальный адрес для каждого пользователя. Я генерирую адресную информацию (город, улица, штат и т. Д.) На основе информации, возвращаемой картами Google, а затем сохраняю информацию lat / long в базе данных. Это не позволяет вам перекодировать вещи и дает вам хорошо отформатированные адреса.

Еще одна причина, по которой вы хотите это сделать, состоит в том, что существует ежедневный лимит на количество адресов, которые могут быть геокодированы из конкретный IP-адрес. Вы не хотите, чтобы ваше приложение терпело неудачу для человека по этой причине.

6
ответ дан Zachary Wright 18 August 2018 в 05:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: