2015-12-20 2 views
3

Я новичок в node.js, поэтому перед выпуском моего приложения node.js мне нужно быть уверенным, что он будет работать так, как должен.node.js - взаимная переменная

Скажем, у меня есть массив переменных и я инициализировать его на начало моего сценария

myArray = []; 

затем я тяну некоторые данные из внешнего API, хранить внутри туАггау, и использовать метод setInterval(), чтобы вытащить эти данные снова каждые 30 минут:

pullData(); 
setInterval(pullData, 30*60*1000); 

Функция pullData() занимает около 2-3 секунд, чтобы закончить.

Клиенты смогут получить туАггау с помощью этой функции:

http.createServer(function(request, response){ 
var path = url.parse(request.url).pathname; 
if(path=="/getdata"){ 

    var string = JSON.stringify(myArray); 
    response.writeHead(200, {'Content-Type': 'text/plain'}); 
    response.end(string);    

} 
}).listen(8001); 

Так что я спрашиваю, может следующая ситуация произойдет ?: Клиент пытается получить данные из этого node.js сервера, и в тот же момент данные записываются в myArray функцией pullData(), что приводит к недействительным данным, отправляемым клиенту?

Я прочитал документацию, и я понял, что при запуске pullData() createServer() не будет отвечать на запросы клиентов до тех пор, пока pullData() не завершит свою работу? Я действительно плохо разбираюсь в параллельном программировании, поэтому мне нужно ваше подтверждение на этом, или если у вас есть лучшее решение?

EDIT: Вот код моей функции pullData():

var now = new Date(); 

Date.prototype.addDays = function(days){ 

     var dat = new Date(this.valueOf()); 
     dat.setDate(dat.getDate() + days); 
     return dat; 
} 


var endDateTime = now.addDays(noOfDays); 
var formattedEnd = endDateTime.toISOString(); 

var url = "https://api.mindbodyonline.com/0_5/ClassService.asmx?wsdl"; 
    soap.createClient(url, function (err, client) { 
     if (err) { 
      throw err; 
     } 

     client.setEndpoint('https://api.mindbodyonline.com/0_5/ClassService.asmx'); 
     var params = { 
      "Request": { 
       "SourceCredentials": { 
        "SourceName": sourceName, 
        "Password": password, 
        "SiteIDs": { 
         "int": [siteIDs] 
        } 
       }, 
       "EndDateTime" : formattedEnd 

      } 
     }; 


client.Class_x0020_Service.Class_x0020_ServiceSoap.GetClasses(params, function (errs, result) { 
      if (errs) { 
       console.log(errs); 
      } else { 

        var classes = result.GetClassesResult.Classes.Class; 
        myArray = []; 

        for (var i = 0; i < classes.length; i++) { 
         var name = classes[i].ClassDescription.Name; 
         var staff = classes[i].Staff.Name; 
         var locationName = classes[i].Location.Name; 
         var start = classes[i].StartDateTime.toISOString(); 
         var end = classes[i].EndDateTime.toISOString(); 
         var klasa = new Klasa(name,staff,locationName,start,end); 

         myArray.push(klasa); 
        } 

        myArray.sort(function(a,b){ 
         var c = new Date(a.start); 
         var d = new Date(b.start); 
         return c-d; 
        }); 

        string = JSON.stringify(myArray); 
    } 
     }) 


    }); 
+1

Почему вы не используете базу данных для хранения данных? Загрузите его, если вам нужна производительность. Кроме того, если вы начнете масштабирование с помощью нескольких машин, каждая машина получит другой «myArray», и ответ, который получит клиент, будет зависеть от машины, которая получает запрос! Это будет отлично работать для небольшого сервера, и данные будут сохранены до перезапуска сервера! – rohithpr

+0

Это не проблема, так как данных, которые нужно сохранить, не так много, и при каждом запуске серверных данных снова вытягивается, поэтому нет проблем с потерями данных при перезапуске сервера. Я бы не усложнил его с помощью базы данных. Спасибо за ваш ответ в любом случае :) – kecman

ответ

3

Нет, NodeJs не является многопоточным, и все работает на одном потоке, это означает, что кроме неблокирующих вызовов (т.е. IO) все остальное будет задействовать процессор до тех пор, пока он не вернется, и NodeJS абсолютно не вернет полу- путь к заполненному массиву до конечного пользователя, до тех пор, пока вы выполняете только один HTTP-запрос для заполнения вашего массива.

Update: Как отметил @RyanWilcox любой асинхронный (без блокировки системных вызовов) вызов может намекнуть интерпретатор NodeJS оставить выполнение функции на полпути и вернуться к нему позже.

+1

«пока вы выполняете только один HTTP-запрос, чтобы заполнить ваш массив». <- очень важный момент ... хотя это не просто HTTP-вызовы, но * любая асинхронная операция *. – RyanWilcox

+0

@Boynux, пожалуйста, посмотрите на мою функцию pullData(), я просто добавил ее в первый пост и посмотрю, будет ли это работать нормально? – kecman

+0

Трудно ответить, если я предполагаю, что метод GetClasses от клиента мыла не выполняет асинхронный вызов и просто вызывает ваш обратный вызов с данными, да, это безопасно. – Boynux

2

В общем: Нет

JavaScript однопоточен. В то время как одна функция работает, никакая другая функция не может быть.

Исключение - если у вас есть задержки между функциями, которые обращаются к значению массива.

например.

var index = i; 
function getNext() { 
    async.get(myArray[i], function() { 
     i++; 
     if (i < myArray.length) { 
      getNext() 
     } 
    }); 
} 

... в этом случае массив может быть обновлен между вызовами асинхронной функции.

Вы можете уменьшить это путем создания массива deep copy при запуске первой операции async.

+0

Спасибо за ваш обширный ответ. Моя функция pullData обновляет myArray только один раз за каждые 30 минут, так что это должно быть хорошо;) – kecman

2

Javascript - это однопоточный язык, поэтому вам не нужно беспокоиться об этом параллелизме. Это означает, что две части кода не выполняются одновременно. В отличие от многих других языков программирования, у javascript есть другая модель параллелизма, основанная на event loop. Чтобы достичь наилучшей производительности, вы должны использовать неблокирующие операции, выполняемые функциями обратного вызова, обещаниями или событиями. Я полагаю, что ваш внешний API предоставляет некоторые асинхронные функции ввода-вывода, которые хорошо подходят для node.js.

1

Если ваш вызов pullData не занимает слишком много времени, другим решением является кэширование данных.

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

разборе также массив JSON ..

var string = JSON.stringify(myArray); 

..might быть сделано за пределами GetData вызова /, так что это не должно быть сделано для каждого клиента посещения/GetData. Может сделать это немного быстрее.

+0

Получение данных только тогда, когда это не требуется, из-за ограничения числа вызовов API, он должен быть один раз в 30 минут, а свежесть вытащенных данных не так важна, 30 минут это нормально. И спасибо за совет о перемещении строки stringify() строки из/getdata call, она должна немного откликаться на ответы. – kecman

+0

Возможно, мой ответ был недостаточно ясен. Вы не будете получать чаще, чем каждые 30 минут, если вы правильно используете кеширование. Это произойдет снова, если кешированные данные будут старше 30 минут. Фактически, если за два часа есть только один посетитель, у вас будет только один вызов для api вместо четырех (четыре звонка необходимы, если вы используете интервал 30 минут). – peerbolte