Это второй блог из серии Асинхронное программирование, предназначенный для лучшего понимания этого блога и понимания концепций, рассмотренных в части 1 (https://medium.com/@thakurarpitpundir73/asynchronous-programming-the-complete-series-c1e33b2df46f?source=friends_link&sk =13dde96dc175661762d890e0b22d72c8 ) является обязательным условием.
До сих пор мы знаем, что такое асинхронное программирование и зачем оно нам нужно, мы знаем такие понятия, как цикл событий, очередь обратного вызова и стек вызовов, мы также знаем, как делать запросы и получать данные с сервера. Но мы не сделали ничего существенного с данными, которые мы получили с сервера. Давайте попробуем несколько возможных подходов для этого и посмотрим, почему они не работают.
Зачем нужны callback-функции?
Создайте два js-файла: сначала app.js, в этом файле мы будем иметь дело с внутренней работой запроса, а во втором httpsRequest.js в этом файле мы будем просто вызывать функции request.js для получения данных с сервера, а затем использовать это данные. Сначала давайте сделаем запрос в request.js на сервер, чтобы получить случайную головоломку, которую мы используем тот же API, что и в предыдущем блоге.
//In httpRequest.js let getPuzzle = (callback)=>{ request.open("GET", "http://puzzle.mead.io/puzzle?wordCount=3"); request.send(); let request = new XMLHttpRequest(); request.addEventListener("readystatechange", (e) => { if(e.target.readyState === 4 && e.target.status === 200){ let data = JSON.parse(e.target.responseText); //console.log(data.puzzle) return data; }else if(request.readyState === 4){ throw new Error("An error has occured"); } } } });
Мы будем вызывать эту функцию из нашего файла app.js, чтобы получить головоломку с сервера, чтобы мы могли использовать эту головоломку в соответствии с нашими потребностями.
//In app.js const puzzle = getPuzzle(); console.log(puzzle);
Попробуйте этот вывод кода может быть не таким, как вы ожидаете, т. е. «неопределенным». Должно быть что-то не так с нашим кодом или в нашем запросе, давайте попробуем его отладить. Раскомментируйте console.log(data.puzzle), чтобы увидеть, получаем ли мы данные или нет, и снова запустите код.
Вы бы увидели что-то вроде этого. Итак, мы получаем данные с сервера в файле httpsRequest.js, но не можем использовать их в app.js.
Причина в том, что вы не возвращаете данные в переменную головоломки в app.js, а возвращаете данные из анонимной функции, которая передается в качестве аргумента в eventlistener, в функцию, из которой вызывается эта анонимная функция, которая сама является getData(). Взгляните на код еще раз, все станет для вас понятным.
К настоящему времени вы, возможно, уже догадались о решении этой проблемы. Мы объявим переменную в getData.js, сохраним наши данные в этой переменной и затем вернем эту переменную из getData.js в app.js. Давайте попробуем
let getPuzzle = ()=>{ let request = new XMLHttpRequest(); request.open("GET", "http://puzzle.mead.io/puzzle?wordCount=3"); request.send(); let data; request.addEventListener("readystatechange", (e) => { if(e.target.readyState === 4 && e.target.status === 200){ data = JSON.parse(e.target.responseText); console.log(data.puzzle); }else if(request.readyState === 4){ console.log("An error has occurred"); } }); return data; }
Удивительно, но это тоже не решает нашу проблему, и мы все еще получаем неопределенность, хотя наша головоломка хранится в нашей переменной данных.
На этот раз проблема заключается в том, что функция addEventListener срабатывает, когда мы получаем ответ от сервера, но оставшийся код вместе с оператором возврата является частью нашего кода «сейчас». Как вы знаете, код «сейчас» будет выполняться, не дожидаясь ответа от нашего сервера, поэтому во время выполнения оператора возврата мы еще не присвоили какие-либо данные переменной «данные». Вот почему мы видим undefined на консоли.
Решение проблемы с использованием функций обратного вызова
Функция обратного вызова, функция, которая передается другой функции в качестве аргумента, а затем вызывается из этой функции.
Функции обратного вызова могут решить нашу проблему невозможности использовать данные запроса из нашей функции события. Как? Мы передадим наши инструкции в виде функции функции getData(), а затем мы вызовем эту функцию с данными, возвращенными нашим запросом, для использования любым способом, который мы хотим, в этом случае мы просто напечатаем их. Посмотрите код ниже, все это будет иметь смысл.
//In app.js getPuzzle((error,puzzle) => { if(error){ console.log(error); }else{ console.log(puzzle); } });
На этот раз мы передали функцию обратного вызова в качестве аргумента для getPuzzle(), и эту функцию можно вызвать из getPuzzle(), когда у нас есть данные.
let getPuzzle = (callback)=>{ let request = new XMLHttpRequest(); request.open("GET", "http://puzzle.mead.io/puzzle?wordCount=3"); request.send(); request.addEventListener("readystatechange", (e) => { if(e.target.readyState === 4 && e.target.status === 200){ let data = JSON.parse(e.target.responseText); callback(undefined, data); //In this case we have got our data so the for error we will send undefined }else if (e.target.readyState === 4){ callback("An error has occured"); //In case of an error we will pass only one argument the error string ,second argument would be undefined. } }); }
На этот раз мы все сделали правильно, и мы можем использовать данные, возвращаемые нашим запросом, из нашей функции, запускаемой событием.
Если это кажется вам немного простым, позвольте мне задать вам вопрос, поскольку мы обсуждали ранее, что наша функция getData() выполняется до того, как мы получим ответ от сервера, что означает, что все ее аргументы, включая функции обратного вызова, переменную и саму функцию, будут быть удалены из стека вызовов, чтобы освободить память, то как мы все еще можем получить доступ к функции обратного вызова, даже если она больше не существует, мы обсудим эту проблему в следующей части этой серии блогов.
Ваши обзоры важны для меня, чтобы писать лучший контент, я был бы рад услышать от вас.
https://www.linkedin.com/in/arpit-pundir-091094153/
https://www.facebook.com/arpit.pundir.904
https://www.instagram.com/_thakurarpit_/
использованная литература
Вы не знаете Js, https://www.udemy.com/course/modern-javascript/, mdn docs.