Async Programming
Why async?
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
Why async?
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
This operation does not depend on the loaded file. Why, then, are we waiting for it to be loaded first?
Why async?
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
This line is blocking the rest of the code
Why async?
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Why async?
This read operation no longer blocks the execution. "hello" will be logged before the file content, even though it appears later in the code
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Event Loop
Event Loop
JavaScript is a single-threaded programming language, meaning it has only a single thread
Event Loop
Call stack
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
main()
The call stack stores the function calls. If we invoke a function, we insert it into the call stack, when this function returns, we pop the function out of the stack
Event Loop
Call stack
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
main()
require('fs')
The call stack stores the function calls. If we invoke a function, we insert it into the call stack, when this function returns, we pop the function out of the stack
Event Loop
Call stack
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
main()
readFileSync(...)
The call stack stores the function calls. If we invoke a function, we insert it into the call stack, when this function returns, we pop the function out of the stack
Event Loop
Call stack
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
main()
readFileSync(...)
... taking to long...
The call stack stores the function calls. If we invoke a function, we insert it into the call stack, when this function returns, we pop the function out of the stack
Event Loop
Call stack
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
main()
console.log(...)
The call stack stores the function calls. If we invoke a function, we insert it into the call stack, when this function returns, we pop the function out of the stack
Event Loop
Call stack
const fs = require('fs');
const file_data = fs.readFileSync('file.txt', 'utf8');
console.log("Data inside the file:: " + file_data);
console.log("Hi there!");
main()
The call stack stores the function calls. If we invoke a function, we insert it into the call stack, when this function returns, we pop the function out of the stack
console.log(...)
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
Task queue
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
require('fs')
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
readFile(... callback())
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback function
readFile(... callback())
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
callback function
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
console.log()
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
Done?
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
Event loop
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
console.log()
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
callback()
Event Loop
Call stack
main()
The task queue stores tasks to be executed later. The event loop will be watching it.
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', function (err, data) {
if (err) throw err;
console.log("Data inside the file:: " + data)
});
console.log("hello")
Task queue
(function() {
console.log('1');
setTimeout(function cb() {
console.log('2');
}, 10);
console.log('3');
setTimeout(function cb1() {
console.log('4');
}, 20);
console.log('5');
})();
What is going to be the logging order?
Activity #1 - callbacks: call me maybe?
Activity #1 - callbacks: call me maybe?
(function() {
console.log('1');
setTimeout(function cb() {
console.log('2');
}, 10);
console.log('3');
setTimeout(function cb1() {
console.log('4');
}, 20);
console.log('5');
})();
What is going to be the logging order?
1, 3, 5, 2, 4
Activity #2 - Chaining callbacks: highway to hell
(function() {
console.log("Calling the async functionality");
setTimeout(function initialCB() {
console.log('Beginning');
setTimeout(function cb() {
console.log('Reading the folder');
setTimeout(function cb1() {
console.log('Going through the files');
});
});
});
console.log("After async");
})();
Activity #2 - Chaining callbacks: highway to hell
(function() {
console.log("Calling the async functionality");
setTimeout(function initialCB() {
console.log('Beginning');
setTimeout(function cb() {
console.log('Reading the folder');
setTimeout(function cb1() {
console.log('Going through the files');
});
});
});
console.log("After async");
})();
Async block
Activity #2 - Chaining callbacks: highway to hell
What if we want to perform some more async methods on these files?
Activity #2 - Chaining callbacks: highway to hell
(function() {
console.log("Calling the async functionality");
setTimeout(function initialCB() {
console.log('Beginning');
setTimeout(function cb() {
console.log('Reading the folder');
setTimeout(function cb1() {
console.log('Going through the files');
setTimeout(function cb2() {
console.log("Transform this data");
});
});
});
});
console.log("After async");
})();
Activity #2 - Chaining callbacks: highway to hell
What if we want to perform even more async methods?
Activity #2 - Chaining callbacks: highway to hell
What if we want to perform even more async methods?
Activity #2 - Chaining callbacks: highway to hell
(function() {
console.log("Calling the async functionality");
setTimeout(function initialCB() {
console.log('Beginning');
setTimeout(function cb() {
console.log('Reading the folder');
setTimeout(function cb1() {
console.log('Going through the files');
setTimeout(function cb2() {
console.log("Transform this data");
setTimeout(function cb3() {
console.log("Transform this data");
setTimeout(function cb4() {
console.log("Transform this data");
setTimeout(function cb5() {
console.log("Transform this data");
});
});
});
});
});
});
});
console.log("After async");
})();
Activity #2 - Chaining callbacks: highway to hell
(function() {
console.log("Calling the async functionality");
setTimeout(function initialCB() {
console.log('Beginning');
setTimeout(function cb() {
console.log('Reading the folder');
setTimeout(function cb1() {
console.log('Going through the files');
setTimeout(function cb2() {
console.log("Transform this data");
setTimeout(function cb3() {
console.log("Transform this data");
setTimeout(function cb4() {
console.log("Transform this data");
setTimeout(function cb5() {
console.log("Transform this data");
setTimeout(function cb6() {
console.log('Reading the folder');
setTimeout(function cb7() {
console.log('Going through the files');
setTimeout(function cb8() {
console.log("Transform this data");
setTimeout(function cb9() {
console.log("Transform this data");
setTimeout(function cb10() {
console.log("Transform this data");
setTimeout(function cb11() {
console.log("Transform this data");
setTimeout(function cb12() {
console.log("Transform this data");
setTimeout(function cb13() {
console.log('Reading the folder');
setTimeout(function cb14() {
console.log('Going through the files');
setTimeout(function cb15() {
console.log("Transform this data");
setTimeout(function cb16() {
console.log("Transform this data");
setTimeout(function cb17() {
console.log("Transform this data");
setTimeout(function cb18() {
console.log("Transform this data");
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
console.log("After async");
})();
Activity #2 - Chaining callbacks: highway to hell
(function() {
console.log("Calling the async functionality");
setTimeout(function initialCB() {
console.log('Beginning');
setTimeout(function cb() {
console.log('Reading the folder');
setTimeout(function cb1() {
console.log('Going through the files');
setTimeout(function cb2() {
console.log("Transform this data");
setTimeout(function cb3() {
console.log("Transform this data");
setTimeout(function cb4() {
console.log("Transform this data");
setTimeout(function cb5() {
console.log("Transform this data");
setTimeout(function cb6() {
console.log('Reading the folder');
setTimeout(function cb7() {
console.log('Going through the files');
setTimeout(function cb8() {
console.log("Transform this data");
setTimeout(function cb9() {
console.log("Transform this data");
setTimeout(function cb10() {
console.log("Transform this data");
setTimeout(function cb11() {
console.log("Transform this data");
setTimeout(function cb12() {
console.log("Transform this data");
setTimeout(function cb13() {
console.log('Reading the folder');
setTimeout(function cb14() {
console.log('Going through the files');
setTimeout(function cb15() {
console.log("Transform this data");
setTimeout(function cb16() {
console.log("Transform this data");
setTimeout(function cb17() {
console.log("Transform this data");
setTimeout(function cb18() {
console.log("Transform this data");
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
console.log("After async");
})();
Problems with callback style
1. Complex error handling
Problems with callback style
1. Complex error handling
2. Callback hell
Promises in-depth
Promises work like callback functions, in fact, promises are built on top of callback functions. Promises make it way easier to deal with async code. You have to keep in mind two main differences when dealing with promises: using promises and defining promises
Defining promises
function createAsyncFunction () {
return new Promise(function (resolve, reject) {
// Do something
if (allGood) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
Promises in-depth
Promises work like callback functions, in fact, promises are built on top of callback functions. Promises make it way easier to deal with async code. You have to keep in mind two main differences when dealing with promises: using promises and defining promises
p.then((result) => {
// do something with the result
})
.catch((err) => {
// do something with error
})
Using promises
Promises in-depth
Promises work like callback functions, in fact, promises are built on top of callback functions. Promises make it way easier to deal with async code. You have to keep in mind two main differences when dealing with promises: using promises and defining promises
try {
let v = await p();
} catch(e) {
Log.fatal(e)
}
Using promises
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
Defining an async method using promise
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
Using the previously defined async method
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
This function can only be used asynchronously
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
A promise returns 2 callbacks that you must use to settle the promise
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
resolve the promise if all good
reject otherwise
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
Call the method (which is async)
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
Continue with the normal execution (remember the call stack)
Promises in-depth
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
When the function returns, we enter the `then()` or `catch()`
Promises in-depth
Chaining promises
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
Chaining async callbacks
Chaining promises
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
Chaining promises
Chaining promises
try {
let result = await doSomething()
let nextResult = await doSomethingElse(result)
let finalResult = await doThirdThing(nextResult)
console.log('Got the final result: ' + finalResult);
} catch {
//failureCallback
}
Chaining promises with async/await
Many promises and promises.all()
There are cases where you want to perform the same async action multiple times and wait for all of them to finish in order to continue with the workflow.
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
Define async function
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
Run many promises
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
Run this only when ALL promises are fulfilled
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
All promises fulfilled, run this.
Many promises and promises.all()
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var asyncMethod = function() {
var promise = new Promise(function(resolve, reject){
setTimeout(function() {
console.log('Async method completed');
resolve({status: 200});
}, getRandomInt(5)*1000 );
});
return promise;
};
console.log("Starting to create many promises")
var p1 = asyncMethod()
var p2 = asyncMethod()
var p3 = asyncMethod()
var p4 = asyncMethod()
var p5 = asyncMethod()
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log("done: " + JSON.stringify(values))
});
console.log("I'm going to run before all these guys!");
Hint: you will want to use this when parsing a single course file. A single course file == a promise. Many of these promises == your dataset.
.all() them all
Testing async methods
it('should do something with promises', function() {
var blah = 'foo';
var result = asyncMethod();
return result.then(function(data) {
expect(data).to.equal(blah);
})
.catch(function(err) {
Log.test("Something went wrong. Message: " + err);
expect.fail();
})
});
Using .then() and .catch()
Testing async methods
it('should do something with promises', function() {
var blah = 'foo';
var result = asyncMethod();
return result.then(function(data) {
expect(data).to.equal(blah);
})
.catch(function(err) {
Log.test("Something went wrong. Message: " + err);
expect.fail();
})
});
Using .then() and .catch()
Blocks the test flow and waits for the return
Testing async methods
it('should do something with promises', function() {
var blah = 'foo';
var result = asyncMethod();
return result.then(function(data) {
expect(data).to.equal(blah);
})
.catch(function(err) {
Log.test("Something went wrong. Message: " + err);
expect.fail();
})
});
Using .then() and .catch()
Testing async methods
it("Should add a valid dataset", async () => {
const id: string = "courses";
const expectedCode: number = 204;
let response: InsightResponse;
try {
response = await insightFacade.addDataset(id,
datasets[id],
InsightDatasetKind.Courses);
} catch (err) {
response = err;
} finally {
expect(response.code).to.equal(expectedCode);
}
});
Using async/await
Common mistake
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
var number;
generateRandomNumber().then(function(result) {
number = result;
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
console.log(number);
Common mistake
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
var number;
generateRandomNumber().then(function(result) {
number = result;
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})
console.log(number);
What's going to be logged?
Resources
deck
By Rodrigo Araújo
deck
- 2,074