Javascript Promises
Agenda
- Callback Review
- Using a Promise
- Making a Promise
- Interesting Uses
- Quiz
db.query("SELECT * FROM students", function(err, students) {
if(err) {
logger.error(err);
return;
}
//do stuff with students
});
db.query("SELECT * FROM students", function(err, students) {
if(err) {
logger.error(err);
return;
}
db.query("SELECT * FROM teachers", function(err, teachers) {
if(err) {
logger.error(err);
return;
}
//do stuff with students and teachers
});
});
var students, teachers;
db.query("SELECT * FROM students", function(err, _students) {
if(err) {
logger.error(err);
return;
}
students = _students;
if(students && teachers) {
//do stuff with students and teachers
}
});
db.query("SELECT * FROM teachers", function(err, _teachers)
if(err) {
logger.error(err);
return;
}
teachers = _teachers;
if(students && teachers) {
//do stuff with students and teachers
}
});
Callbacks Don't Compose
- Circa 2012
- Unified API
- Holds a single value
- .then()
- In a state of
- Pending
- Resolved
- Rejected
What is a Promise?
- ES6
-
Native in:
- Node
- Chrome
- FF
- Safari
- Edge
Where I can use them?
- .then(onResolve, [onReject])
- .catch(onReject)
Using a Promise
Using a Promise
promise
.then((value) => {
//do something with value
})
.catch((err) => {
//handle an error
});
Using a Promise
promise
.then((value) => {
//do something with value
}, (err) => {
//handle an error
});
Errors and Rejections
promise
.then((value) => {
return 1;
})
.catch((err) => {
// won't be called
});
Errors and Rejections
promise
.then((value) => {
return Error("WAT");
})
.catch((err) => {
// won't be called
});
Errors and Rejections
promise
.then((value) => {
throw Error("WAT");
})
.catch((err) => {
// WILL be called
});
Chaining
promise
.then((value) => {
//do something with value
})
.then((value) => {
//do something else
})
.catch((err) => {
//handle an error
})
.then(() => {
// do something later
// even after an error
});
Composing
promise
.then((value) => {
return anotherPromise
.then(() => {
console.log("This will run first.");
});
})
.then(() => {
console.log("This will run second.");
})
.catch((err) => {
// handle an error in
// any of the promises
});
Composing
Promise.all([
promise1,
promise2,
promise3
])
.then((values) => {
// do something with all three
})
.catch((err) => {
// handle an error in
// any of the promises
});
Composing
var ids = [1, 2, 3, 4, 5, 6];
var promises = ids.map((id) => fetch(id));
Promise.all(promises)
.then((values) => {
// do something with all six
})
.catch((err) => {
// handle an error in
// any of the promises
});
Creating Promises
Promise.resolve(17);
Promise.reject(Error("NOPE"));
new Promise((resolve, reject) => {
});
Creating Promises
db.query = function(sql, callback) {
// 3rd party code that we don't control
}
db.promiseQuery = function(sql) {
return new Promise((resolve), reject) => {
db.query(sql, function(err, results) {
if(err) {
reject(err);
}
else {
resolve(results);
}
});
});
}
var students, teachers;
db.query("SELECT * FROM students", function(err, _students) {
if(err) {
logger.error(err);
return;
}
students = _students;
if(students && teachers) {
//do stuff with students and teachers
}
});
db.query("SELECT * FROM teachers", function(err, _teachers)
if(err) {
logger.error(err);
return;
}
teachers = _teachers;
if(students && teachers) {
//do stuff with students and teachers
}
});
Promise.all([
db.promiseQuery("SELECT * FROM students"),
db.promiseQuery("SELECT * from teachers")
]).then((results) => {
var students = results[0];
var teacher = results[1];
//do stuff with students and teachers
}).catch((err) => {
logger.error(err);
});
Promise.all(promises)
Promise.race(promises)
Promise.resolve(resolvedValue);
Promise.reject(rejectedValue);
new Promise((resolve, reject) => {
})
.then(onResolve, [onReject])
.catch(onReject)
Promises API
Where are Promises used in LT?
- Everywhere! ;)
- All Redis queries
- All HTTP Requests
- Run to completion, or
- time out after 30 seconds
LT Load Test
var timeoutPromise = function(delay) {
return new Promise((resolve, reject) => {
setTimeout(reject, delay);
});
}
Promise.race([
loadTestCompletionPromise,
timeoutPromise(30 * 1000)
]).then(() => {
// load test succeeded! :)
}).catch(() => {
// load test timed out! :(
});
LT Load Test
Chunking
- 100,000 promises
- Promise.all() would crush the system
var ids = [1, 2, 3, ..., 100000];
var chunks = _.chunk(ids, 5000);
sessionStore.findAll(chunks[0])
.then((sessions) => {
//do stuff
})
.then(() => {
return sessionStore.findAll(chunks[1]);
})
.then((sessions) => {
//do more stuff
})
.then(() => {
return sessionStore.findAll(chunks[2]);
})
//etc.
Chunking
var ids = [1, 2, 3, ..., 100000];
var chunks = _.chunk(ids, 5000);
var promiseGenerators = chunks.map((chunk) => {
function() {
return sessionStore.findAll(chunk);
}
});
promiseGenerators.reduce((memo, f) => {
memo.then(f);
}, Promise.resolve([]));
Chunking
Quiz Time!
function doStuff() {
return Promise.resolve(17);
}
doStuff()
.then(() => {
console.log('first');
})
.then(() => {
console.log('second')
})
.catch((err) => {
console.log('REJECTED!')
});
function doStuff() {
return Promise.reject(17);
}
doStuff()
.then(() => {
console.log('first');
})
.then(() => {
console.log('second')
})
.catch((err) => {
console.log('REJECTED!')
});
function doStuff() {
return Promise.reject(17);
}
doStuff()
.catch((err) => {
console.log('REJECTED!')
})
.then(() => {
console.log("AFTER REJECTION!");
})
.catch(() => {
console.log("I'M STILL REJECTED!");
});
function doStuff() {
return Promise.resolve(17);
}
function sayHello(name) {
return Promise.resolve("Hi, " + name);
}
doStuff()
.then((value) => {
console.log("Value is: " + value);
return Promise.all([
sayHello("Joel"),
sayHello("Manda")
]);
})
.then((greetings) => {
greetings.forEach(g => console.log(g));
});
function doStuff() {
return Promise.resolve(17);
}
var p = doStuff();
p.then(() => Promise.reject(Error("NOPE")))
p.then((value) => {
console.log("SUCCESS!");
})
.catch((err) => {
console.log("ERROR!");
});
Promise.resolve(this.talk);
promises
By Chris Geihsler
promises
- 1,291