Как избежать объявления глобальных переменных в этом случае? - PullRequest
0 голосов
/ 12 января 2019

Если у меня есть функция с вызовом ajax, которая получает какое-то значение из базы данных, а затем мне нужно отправить это значение обратно в скрипт php и так далее, как мне объявить эту переменную?

function call(id){
  $.ajax({
    . . .
    data: {id: id},
    success: function(res){
       window.id = res.id
     }
  });
}


//first call the function with a value
 call(10);

//then call it with the returned value every time the btn gets clicked

$('#btn').click(function(){
 call(window.id);
})

Насколько я понимаю, плохая практика - использовать такие глобальные переменные, потому что глобальная область уже переполнена, и скрипту требуется больше времени для поиска этой переменной. Могу ли я определить это значение таким образом, чтобы я мог отправить его обратно, не будучи глобальным?

Ответы [ 3 ]

0 голосов
/ 12 января 2019

Самый простой способ избежать глобализаций - это вообще не работать в глобальном масштабе. Способ сделать это - создать IIFE (выражение для немедленного вызова функции), которое является анонимной функцией, находящейся в глобальной области видимости, но, поскольку она анонимна, у нее нет шансов столкнуться с другой функцией с одно и то же имя Он немедленно вызывается для выполнения кода внутри него (например, операция типа init). Затем внутри этой функции вы делаете то, что обычно делаете. Здесь вы можете создать переменную в области IIFE (не глобальной).

// IIFE wrapper
(function(){

  let mainID = null; // IIFE scoped variable

  function call(id){
    $.ajax({
      . . .
      data: {id: id},
      success: function(res){
         mainID = res.id; // Set the IIFE scoped variable to the AJAX result
       }
    });
  }

  // Set up the event
  $('#btn').click(function(){
    all(res.id);  // <-- And, you can use it anywhere in the IIFE
  });

  call(10);        // first call the function with a value

})();  // <-- The extra set of parenthesis is what invokes the expression 

С другой стороны, ваш код не будет работать даже при этом, потому что вы настраиваете обработчик события click кнопки до того, как вызов AJAX сможет завершиться. Тот факт, что этот код идет после асинхронного кода, не означает, что он будет выполняться после асинхронного кода. Весь смысл асинхронной операции в том, что мы не знаем, когда она завершится, и, поскольку JavaScript работает в однопоточной среде, в то время как асинхронная операция идет своим делом, текущая функция выполняется до конца. Только после того, как текущий поток простаивает, будут вызваны результаты асинхронной операции (обратный вызов успеха). Если обработчик событий полагается на результат вызова AJAX, вам необходимо настроить обработчик событий внутри обратного вызова «success», что в любом случае делает глобальную бессмысленной потребность. Вы все равно должны поместить весь свой код в IIFE, так как это лучшая практика.

Вот пример, который показывает другой тип асинхронной операции (таймер), который все еще работает так же, как ваш AJAX-вызов, который показывает проблему:

// Global variable
var result = null;

// Start an async operation that will execute the callback
// after three seconds:
setTimeout(function(){
  result = "complete"
  console.log("Async operation " + result);
}, 3000);

// This function will run before the async operation 
// completes, so the use of the variable that is set
// by the async operation will fail
console.log("Local operation " + result);

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

// IIFE wrapper
(function(){

  function call(id){
    $.ajax({
      . . .
      data: {id: id},
      success: function(res){
        // Set up the event now that the AJAX call is complete
        $('#btn').click(function(){
          call(res.id);
        });
       }
    });
  }

  call(10);        // first call the function with a value

})();  // <-- The extra set of parenthesis is what invokes the expression

Вот рабочий пример всего этого:

(function(){
  // IIFE scoped variables
  let btn = document.querySelector("button");
  let random = null;

  function async(){
    // Async operation complete! 
    
    // Generate a random number that simulates the
    // DB response that would now be available
    random = Math.floor(Math.random() * 11);  
    
    // Enable the button:   
    btn.removeAttribute("disabled");
    
    // Set up the button's click event handler
    btn.onclick = function(){
      console.log("Button clicked. ID = " + random);
      async(); 
    };
    
  }
  
  // Start an async operation that will execute the callback
  // after three seconds:
  setTimeout(async, 3000);
})();
<button type="button" disabled>Click Me</button>
0 голосов
/ 12 января 2019

Просто замените window.id на call.id (то есть сохраните его как свойство вашей функции):

function call(id){
  $.ajax({
    . . .
    data: {id: id},
    success: function(res){
       call.id = res.id
     }
  });
}


//first call the function with a value
call(10);

//then call it with the returned value every time the btn gets clicke
$('#btn').click(function(){
  call(call.id);
})
0 голосов
/ 12 января 2019

Поскольку id семантически привязан к #btn, вы можете сохранить возвращенное значение id как свойство #btn:

function call(id){
  $.ajax({
    . . .
    data: {id: id},
    success: function(res){
       $('#btn').prop('response_id', res.id);
     }
  });
}

//first call the function with a value
 call(10);

//then call it with the returned value every time the btn gets clicked

$('#btn').click(function(){
 call(this.prop('response_id'));
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...