console.log('1') console.log('2') console.log('3')
console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')
setTimeout
function was called. The callback will be called, in this example, after 2 seconds. The application will not stop while waiting for the two seconds to expire. Instead, its execution will continue, and when the timer fires, the afterTwoSeconds
function will be called.XMLHttpRequest
(XHR), but you can easily use jQuery ( $.ajax
) here, or the more modern standard approach, based on the use of the function fetch
. Both that and another is reduced to use of promises. The code, depending on the campaign, will change, but here, for a start, this example: // url - 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { // } else { // } } } xhr.ontimeout = function () { // , , } xhr.open('get', url, true) xhr.send(); }
// "doThis" , - "andThenThis". "doThis" , , , , "andThenThis". doThis(andThenThis) // "doThis" "callback" , , , function andThenThis() { console.log('and then this') } // , , , "callback" - function doThis(callback) { console.log('this first') // , , , , , '()', callback() }
request
function: function request(url, callback) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.response) } else { callback(xhr.status, null) } } } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }
callback
parameter, therefore, after executing the request and receiving the server response, the callback will be called both in case of an error and in case of successful completion of the operation. const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users` request(userGet, function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) { request(user.repos_url, function handleReposList(err, repos) { if (err) throw err // }) }) })
handleUsersList
handleUsersList is handleUsersList
;SON.parse
, convert it, for convenience, into an object;repos_url
is the URL for our next requests, and we got it from the first request.handleReposList
. Here, as well as when loading a list of users, you can handle errors or useful data, which contain a list of user repositories. try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) { request(user.repos_url, handleReposList) }) } function handleReposList(err, repos) { if (err) throw err // console.log('My very few repos', repos) }
forEach
loop, here are three, is that such code is hard to read and maintain. A similar problem exists, perhaps, from the day the callback functions appeared, it is widely known as callback hell. const myPromise = new Promise(function(resolve, reject) { // if (codeIsFine) { resolve('fine') } else { reject('error') } }) myPromise .then(function whenOk(response) { console.log(response) return response }) .catch(function notOk(err) { console.error(err) })
resolve
and reject
methods;Promise
constructor. If the code is executed successfully, call the resolve
method, if not, reject
;resolve
, the .then
method for the Promise
object will be executed; similarly, if reject
is called, the .catch
method will be executed.resolve
and reject
methods take only one parameter; as a result, for example, when executing a command of the type resolve('yey', 'works')
, only 'yey'
will be passed to the callback .then
;.then
calls at the end of the corresponding callbacks, you should always use return
, otherwise they will all be executed at the same time, and this is obviously not what you want to achieve;reject
command is executed, if the next in the chain goes .then
, it will be executed (you can consider .then
expression that is executed in any case);.then
calls in one of them, the next ones will be skipped until the expression .catch
is found;resolve
or reject
, as well as the states “resolved” and “rejected”, which correspond to a successful, with a call to resolve
, and unsuccessful, with a call to reject
, completion of the work of promis. When the promise is in the “resolved” or “rejected” state, it cannot be changed. function request(url) { return new Promise(function (resolve, reject) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(xhr.response) } else { reject(xhr.status) } } } xhr.ontimeout = function () { reject('timeout') } xhr.open('get', url, true) xhr.send(); }) }
request
, the following will be returned.request
function, we will rewrite the rest of the code. const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users` const myPromise = request(userGet) console.log('will be pending when logged', myPromise) myPromise .then(function handleUsersList(users) { console.log('when resolve is found it comes here with the response, in this case users ', users) const list = JSON.parse(users).items return Promise.all(list.map(function(user) { return request(user.repos_url) })) }) .then(function handleReposList(repos) { console.log('All users repos in an array', repos) }) .catch(function handleErrors(error) { console.log('when a reject is executed it will come here ignoring the then statement ', error) })
.then
with the successful resolution of promise. We have a list of users. In the second expression .then
we pass an array with repositories. If something went wrong, we’ll end up in a .catch
expression. const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users` const userRequest = request(userGet) // , userRequest .then(handleUsersList) .then(repoRequest) .then(handleReposList) .catch(handleErrors) function handleUsersList(users) { return JSON.parse(users).items } function repoRequest(users) { return Promise.all(users.map(function(user) { return request(user.repos_url) })) } function handleReposList(repos) { console.log('All users repos in an array', repos) } function handleErrors(error) { console.error('Something went wrong ', error) }
.then
expressions reveals the meaning of the call to userRequest
. The code is easy to work with and easy to read.function
. Using generators, asynchronous code can be made very similar to synchronous. For example, it may look like this: function* foo() { yield 1 const args = yield 2 console.log(args) } var fooIterator = foo() console.log(fooIterator.next().value) // 1 console.log(fooIterator.next().value) // 2 fooIterator.next('aParam') // console.log 'aParam'
return
, use the expression yield
, which stops the execution of the function until the next call to the .next
iterator. This is similar to the expression .then
in promises, which is performed when promise is resolved.request
function: function request(url) { return function(callback) { const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { callback(null, xhr.response) } else { callback(xhr.status, null) } } } xhr.ontimeout = function () { console.log('timeout') } xhr.open('get', url, true) xhr.send() } }
url
argument, but instead of immediately executing the request, we want to execute it only when we have a callback function to process the response. function* list() { const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users` const users = yield request(userGet) yield for (let i = 0; i<=users.length; i++) { yield request(users[i].repos_url) } }
request
function, which it receives the url
and returns the function that expects the callback);users
, to be ready to be sent to the next .next
;users
array and expect, for each of them, .next
, returning, for each, the corresponding callback. try { const iterator = list() iterator.next().value(function handleUsersList(err, users) { if (err) throw err const list = JSON.parse(users).items // iterator.next(list) list.forEach(function(user) { iterator.next().value(function userRepos(error, repos) { if (error) throw repos // console.log(user, JSON.parse(repos)) }) }) }) } catch (e) { console.error(e) }
async
, which function is supposed to be performed asynchronously, and using await
, tell the system what part of the code should wait for the permission of the corresponding promise. sumTwentyAfterTwoSeconds(10) .then(result => console.log('after 2 seconds', result)) async function sumTwentyAfterTwoSeconds(value) { const remainder = afterTwoSeconds(20) return value + await remainder } function afterTwoSeconds(value) { return new Promise(resolve => { setTimeout(() => { resolve(value) }, 2000); }); }
sumTwentyAfterTwoSeconds
;afterTwoSeconds
, which can end with a call to resolve
or reject
;.then
, where the operation marked with the await
keyword is completed, in this case it is just one operation.request
function for use in the async/await
construction: function request(url) { return new Promise(function(resolve, reject) { const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(e) { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(xhr.response) } else { reject(xhr.status) } } } xhr.ontimeout = function () { reject('timeout') } xhr.open('get', url, true) xhr.send() }) }
async
, in which we use the await
keyword: async function list() { const userGet = `https://api.github.com/search/users?page=1&q=daspinola&type=Users` const users = await request(userGet) const usersList = JSON.parse(users).items usersList.forEach(async function (user) { const repos = await request(user.repos_url) handleRepoList(user, repos) }) } function handleRepoList(user, repos) { const userRepos = JSON.parse(repos) // console.log(user, userRepos) }
list
function that will process the request. We also need the async/await
construction in a forEach
loop to form a list of repositories. Calling all this is very simple: list() .catch(e => console.error(e))
async/await
can be found here .async/await
, like the minus of the generators, is that the old browsers do not support this design, and for its use in server development you need to use Node 8. In this situation, again, a transpiler will help, for example, babel .async/await
. If you want to properly deal with what we talked about - experiment with this code and with all the technologies discussed.$.ajax
and fetch
. If you have ideas on how to improve the quality of the code using the methods described above, I will be grateful if you tell me about it.Source: https://habr.com/ru/post/337662/
All Articles