Для сценариев на стороне сервера нет 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 объясняет это, в то время как есть локальная Эмулятор для функций облака.
Нет, другого способа не существует: если у вас много мест и вы хотите отображать их на карте, лучшим решением будет следующее:
Это, конечно, учитывая, что у вас намного меньше создания / изменения местоположений, чем у вас есть консультации по местам.
Да, это означает, что вам нужно будет сделать бит больше работы при сохранении местоположений - но это также означает:
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, если вы считаете себя в безопасности обрабатывая более низкую задержку.
Надеюсь, это поможет кому-то в ближайшем будущем;)
Я столкнулся с той же проблемой, пытаясь геокодировать 140 адресов.
Моим обходным путем было добавление usleep (100000) для каждого цикла следующего запроса геокодирования. Если статус запроса OVER_QUERY_LIMIT, спящий режим увеличивается на 50000, и запрос повторяется и т. Д.
И причина, по которой все полученные данные (lat / long) хранятся в файле XML, чтобы не запускать запрос каждый раз, когда страница загружается.
Я только что протестировал 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
}
}
Надеюсь, что это поможет
На самом деле вам не нужно ждать полной секунды для каждого запроса. Я обнаружил, что, если я жду 200 миллисекунд между каждым запросом, я могу избежать ответа OVER_QUERY_LIMIT, и пользовательский интерфейс проходим. С помощью этого решения вы можете загрузить 20 элементов за 4 секунды.
$(items).each(function(i, item){
setTimeout(function(){
geoLocate("my address", function(myLatlng){
...
});
}, 200 * i);
}
К сожалению, это ограничение службы карт Google.
В настоящее время я работаю над приложением, использующим функцию геокодирования, и я сохраняю каждый уникальный адрес для каждого пользователя. Я генерирую адресную информацию (город, улица, штат и т. Д.) На основе информации, возвращаемой картами Google, а затем сохраняю информацию lat / long в базе данных. Это не позволяет вам перекодировать вещи и дает вам хорошо отформатированные адреса.
Еще одна причина, по которой вы хотите это сделать, состоит в том, что существует ежедневный лимит на количество адресов, которые могут быть геокодированы из конкретный IP-адрес. Вы не хотите, чтобы ваше приложение терпело неудачу для человека по этой причине.