The woods are lovely, dark and deep. But I have promises to keep, and miles to go before I sleep. — Robert Frost
p = new Promise((resolve, reject) => {
resolve(10);
resolve(20);
}).then(x => console.log(x));
p = new Promise((resolve, reject) => {
reject(10);
reject(20);
}).catch(x => console.log(x));
p = new Promise((resolve, reject) => {
resolve(10);
reject(20);
}).then(x => console.log(x))
.catch(x => console.log(x));
Promise.resolve(10)
.then(x => console.log(x))
.then(x => console.log(x))
.then(x => console.log(x));
p = Promise.resolve(10);
p.then(x => console.log(x));
p.then(x => console.log(x));
p.then(x => console.log(x));
Promise.resolve(10)
.then(x => {
console.log(x);
return 20;
})
.catch(x => {
console.log(x);
return 30;
})
.then(x => {
console.log(x);
return 40;
})
.then(x => {
console.log(x);
});
Promise.reject(10)
.catch(x => {
console.log(x);
return 20;
})
.then(x => {
console.log(x);
return 30;
})
.catch(x => {
console.log(x);
return 40;
})
.then(x => { console.log(x); });
console.log('start');
setTimeout(() => {
console.log('middle');
}, 0);
console.log('end');
console.log('start');
fs.readFile('a.js', (err, data) => {
console.log(`data - ${data}`);
});
console.log('end');
Concurrency is a way to structure a program by breaking it into pieces that can be executed independently
String fileName = "/Users/folder/source.txt";
File file = new File(fileName);
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line;
while((line = br.readLine()) != null){
//process the line
System.out.println(line);
}
Imagine a hypothetical scenario (where all operations are async) —
class Example {
public static void main(String[] args) {
print('start');
ResultSet rs = st.executeQuery(query);
while (rs.next()) {
// result
}
URL url = new URL("http://www.someserver.com/");
URLConnection connection = url.openConnection();
while ((inputLine = in.readLine()) != null)
response.append(inputLine);
PNG png = transform(picture);
if (png != null) {
sendEmail(user);
}
log('Task')
print('end');
}
}
queryDatabase({ user: 'arfat' }, (err, user) => {
});
queryDatabase({ user: 'arfat' }, (err, user) => {
const image_url = user.profile_img_url;
getPicture(`someServer.com/q=${image_url}`, (err, image) => {
});
});
queryDatabase({ user: 'arfat' }, (err, user) => {
const image_url = user.profile_img_url;
getPicture(`someServer.com/q=${image_url}`, (err, image) => {
transform(picure, (err, png) => {
})
});
});
queryDatabase({ user: 'arfat' }, (err, user) => {
const image_url = user.profile_img_url;
getPicture(`someServer.com/q=${image_url}`, (err, image) => {
transform(picure, (err, png) => {
if (err) {
// handle errors
} else {
sendEmail(user, (err, success) => {
log(success);
});
}
})
});
});
queryDatabase({ user: 'arfat' }, (err, user) => {
const image_url = user.profile_img_url;
getPicture(`someServer.com/q=${image_url}`, (err, image) => {
transform(picure, (err, png) => {
if (err) {
// handle errors
} else {
sendEmail(user, (err, success) => {
log(success);
});
}
})
});
});
Disadvantages of Callbacks
Loss of Error Handling
try {
download(url, function(image) {
image.show();
});
} catch (e) {
// never executed!! console.log("Cannot show image")
}
try {
// is X Asynchronous?!?!
X(url, function(image) {
image.show();
});
} catch (e) {
// never executed!! console.log("Cannot show image")
}
Sync/Async Ambiguity
p = new Promise((resolve, reject) => {
resolve(10);
resolve(20);
}).then(x => console.log(x));
p = new Promise((resolve, reject) => {
reject(10);
reject(20);
}).catch(x => console.log(x));
p = new Promise((resolve, reject) => {
resolve(10);
reject(20);
}).then(x => console.log(x))
.catch(x => console.log(x));
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
An object which represents and manage the lifecycle of a future result
The Promise API
const p = new Promise()
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
An object which represents and manage the lifecycle of a future result
The Promise API
const p = new Promise((resolve, reject) => {
})
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
An object which represents and manage the lifecycle of a future result
The Promise API
const p = new Promise((resolve, reject) => {
setTimeout(resolve, 2000);
})
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
An object which represents and manage the lifecycle of a future result
The Promise API
const p = new Promise((resolve, reject) => {
setTimeout(resolve, 2000);
});
p.then(() => console.log('after 2 seconds'));
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
An object which represents and manage the lifecycle of a future result
The Promise API
const wait = (ms) => new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
wait(2000).then(() => console.log('after 2 seconds'));
A thenable is an object that has a Promise-style then() method.
A Promise object serves as a link between the executor and the consuming functions, which will receive the result or error.
Consumers can be registered using one of the following methods
Promise.prototype.then
Promise.prototype.then(undefined, onRejected)
Promise.prototype.catch
Promise.prototype.finally
You can attach handlers to settled promises later
The consumer callbacks do not have to be attached at the moment of Promise construction.
let promise = new Promise((resolve) =>
setTimeout(() => resolve('done!'), 1000)
).then(console.log);
let promise = new Promise((resolve) =>
setTimeout(() => resolve('done!'), 1000)
);
promise.then(console.log);
They can be attached later.
Solutions
p = new Promise((resolve, reject) => {
resolve(10);
resolve(20);
}).then(x => console.log(x));
// 10
p = new Promise((resolve, reject) => {
reject(10);
reject(20);
}).catch(x => console.log(x));
// 10
p = new Promise((resolve, reject) => {
resolve(10);
reject(20);
}).then(x => console.log(x))
.catch(x => console.log(x));
// 10
Promise.resolve(10)
.then(x => console.log(x))
.then(x => console.log(x))
.then(x => console.log(x));
p = Promise.resolve(10);
p.then(x => console.log(x));
p.then(x => console.log(x));
p.then(x => console.log(x));
Chaining of promises mean that the result of one promise will be fed to the next promise.
Very analogous to the Unix Pipe operator
asyncFunc1()
.then(result1 => {
// Use result1
// A
return asyncFunction2();
})
.then(result2 => {
// Use result2
// B
})
.catch(error => {
// Handle errors of
// asyncFunc1() and asyncFunc2()
});
How the Promise returned by then() is settled depends on what its callback does:
If it returns a Promise (as in line A), the settlement of that Promise is forwarded to P. That’s why the callback from line B can pick up the settlement of asyncFunction2’s Promise.
If it returns a different value, that value is passed.
If it throws an exception then P is rejected with that exception.
Attaching multiple handlers to the same promise
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
});
promise.then(function(result) {
return result * 2;
});
promise.then(function(result) {
return result * 2;
});
promise.then(function(result) {
return result * 2;
});
Promise.resolve(10)
.then(x => console.log(x))
.then(x => console.log(x))
.then(x => console.log(x));
// 10 undefined undefined
p = Promise.resolve(10);
p.then(x => console.log(x));
p.then(x => console.log(x));
p.then(x => console.log(x));
// 10 10 10
Solutions
Error handling with promises
A promise can reject by
Promise.reject(10)
.catch(x => {
console.log(x);
return 20;
})
.then(x => {
console.log(x);
return 30;
})
.catch(x => {
console.log(x);
return 40;
})
.then(x => { console.log(x); });
Example
unhandledRejections
window.addEventListener('unhandledrejection', function(event) {
// the event object has two special properties:
// [object Promise] - the promise that generated the error
alert(event.promise);
// Error: Whoops! - the unhandled error object
alert(event.reason);
});
// Node
process.on('unhandledRejection', (error, promise) => {
console.log(error, promise);
});
new Promise(function() {
throw new Error("Whoops!");
}); // no catch to handle the error
Promise.resolve(10)
.then(x => {
console.log(x);
return 20;
})
.catch(x => {
console.log(x);
return 30;
})
.then(x => {
console.log(x);
return 40;
})
.then(x => {
console.log(x);
});
Test yourself!
const promise = new Promise((resolve, reject) => {
// perform action, call resolve
// or reject upon completion / error
});
promise.then(result => {
// listen for completion
});
promise.then(
result => {} // listen for completion
(error) => {} // listen for error
);
promise.catch(error => {
// listen for error
});
promise.finally(() => {
// cleanup
});
Summary
Promise.reject(10)
.catch(x => {
console.log(x);
return 20;
})
.then(x => {
console.log(x);
return 30;
})
.catch(x => {
console.log(x);
return 40;
})
.then(x => { console.log(x); });
// 10 20 30
Promise.resolve(10)
.then(x => {
console.log(x);
return 20;
})
.catch(x => {
console.log(x);
return 30;
})
.then(x => {
console.log(x);
return 40;
})
.then(x => {
console.log(x);
});
// 10 20 40
const wait = (ms) => new Promise((resolve, reject) => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
setTimeout(() => reject(`Rej-${randomNumber}`), ms);
} else {
setTimeout(() => resolve(`Res-${randomNumber}`), ms);
}
});
wait(2000)
.then(console.log)
.catch(console.log)
.finally((...args) => console.log('done', args.length));
Promise Construction
Aggregate Operations on Promises
Promise.resolve('abc')
.then(x => console.log(x)); // abc
const p = new Promise(() => null);
console.log(Promise.resolve(p) === p); // true
There are 3 major semantic behaviors of resolve
const fulfilledThenable = {
then(resolve, reject) {
resolve('hello');
console.log(typeof reject);
},
};
const promise = Promise.resolve(fulfilledThenable);
console.log(promise instanceof Promise); // true
promise.then((x) => console.log(x)); // hello
The idea is that 3rd-party libraries may implement “promise-compatible” objects of their own.
The static Promise.reject function returns a Promise that is rejected.
Promise.reject(new Error('fail'))
.then(function() {
// not called
}, function(error) {
console.error(error);
});
Promise.resolve(10)
.then(x => {
console.log(x);
return 20;
})
.then(x => {
console.log(x);
throw new Error(30);
})
.then(x => {
console.log(x);
return 40;
})
.catch(x => {
console.log(x);
return 50;
});
Promise.reject(10)
.catch(x => console.log(x))
.catch(x => console.log(x))
.catch(x => console.log(x));
const p = new Promise(res => {
res(10);
});
Promise.reject(p)
.catch((x) => {
console.log('rejected with ', x);
});
Promise.resolve(10)
.then(x => {
console.log(x);
return 20;
})
.then(x => {
console.log(x);
throw new Error(30);
})
.then(x => {
console.log(x);
return 40;
})
.catch(x => {
console.log(x);
return 50;
});
// 10 20 Error(30)
Promise.reject(10)
.catch(x => console.log(x))
.catch(x => console.log(x))
.catch(x => console.log(x));
// 10
const p = new Promise(res => {
res(10);
});
Promise.reject(p)
.catch((x) => {
console.log('rejected with ', x);
});
// rejected with Promise { 10 }
Promise Construction
Aggregate Operations on Promises
Promise.all
Promise.all([
asyncFunc1(),
asyncFunc2(),
])
.then(([result1, result2]) => {
···
})
.catch(err => {
// Receives first rejection among the Promises
···
});
all lets you know when either all input promises have fulfilled or when one of them rejects.
Promise.race
Promise.race([
httpGet('http://example.com/file.txt'),
delay(5000).then(function () {
throw new Error('Timed out')
});
])
.then(function (text) { ··· })
.catch(function (reason) { ··· });
Promise.allSettled
The Promise.allSettled() method returns a promise that resolves after all of the given promises have either settled, with an array of objects that each describes the outcome of each promise.
Promise.allSettled([
Promise.resolve('a'),
Promise.reject('b'),
])
.then(arr => assert.deepEqual(arr, [
{ status: 'fulfilled', value: 'a' },
{ status: 'rejected', reason: 'b' },
]));
Promise.any
const pErr = new Promise((resolve, reject) => {
reject('Always fails');
});
Promise.any([pErr]).catch((err) => {
console.log(err.errors);
});
name | description |
---|---|
Promise.allSettled | does not short-circuit |
Promise.all | short-circuits when an input value is rejected |
Promise.race | short-circuits when an input value is settled |
Promise.any | short-circuits when an input value is fulfilled |
Summary