The Promise
object represents the eventual completion (or failure) of an
asynchronous operation and its resulting value.
The methods promise.then()
, promise.catch()
, and promise.finally()
are used to associate further action with a promise that becomes settled.
For example:
const myPromise = new Promise(function (resolve, reject) {
let sampleData = [2, 4, 6, 8];
let randomNumber = Math.ceil(Math.random() * 5);
if (sampleData[randomNumber]) {
resolve(sampleData[randomNumber]);
} else {
reject('An error occurred!');
}
});
myPromise
.then(function (e) {
console.log(e);
})
.catch(function (error) {
throw new Error(error);
})
.finally(function () {
console.log('Promise completed');
});
These methods are available on Promise.prototype
then
The
.then()
method takes up to two arguments; the first argument is a callback function for the resolved case of the promise, and the second argument is a callback function for the rejected case. Each.then()
returns a newly generated promise object, which can optionally be used for chaining.1
const promise1 = new Promise(function (resolve, reject) {
resolve('Success!');
});
promise1.then(function (value) {
console.log(value);
// expected output: "Success!"
});
catch
A
.catch()
is just a.then()
without a slot for a callback function for the case when the promise is resolved. It is used to handle rejected promises.2
const promise1 = new Promise((resolve, reject) => {
throw 'An error occurred';
});
promise1.catch(function (error) {
console.error(error);
});
// expected output: An error occurred
finally
When the promise is settled, i.e either fulfilled or rejected, the specified callback function is executed. This provides a way for code to be run whether the promise was fulfilled successfully or rejected once the Promise has been dealt with.3
function findDataById(id) {
return new Promise(function (resolve, reject) {
let sampleData = [1, 2, 3, 4, 5];
if (sampleData[id]) {
resolve(sampleData[id]);
} else {
reject(new Error('Invalid id'));
}
});
}
findDataById(4)
.then(function (response) {
console.log(response);
})
.catch(function (err) {
console.error(err);
})
.finally(function () {
console.log('Promise completed');
});
then
, MDN. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then ↩
catch
, MDN. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch ↩
finally
, MDN. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally ↩
In this exercise, you'll be providing a TranslationService
that provides basic translation services to free members, and advanced translation to premium members with quality assurances.
The API
You have found an outer space translation API that fulfills any translation request
in a reasonable amount of time.
You want to capitalize on this.
The space translators are extremely fickle and hate redundancy, so they also provide API storage satellites where you can fetch
past translations without bothering them.
Fetching a translation
api.fetch(text)
fetches a translation of text
from the API storage and returns a promise
that provides two values:
translation
: the actual translationquality
: the quality expressed as a numberIf a translation is not found in the API storage, the API throws a NotAvailable
error.
Translations can be added using the api.request
method.
If 'text' is not translatable, the API throws an Untranslatable
error.
api.fetch('jIyaj');
// => Promise({ resolved: 'I understand' })
Requesting a translation
Some translations are sure to exist, but haven't been added to the API storage yet. That's the difference between NotAvailable
( not in storage, but can be requested ) and Untranslatable
( cannot be translated ).
api.request(text, callback)
requests that a translation of text
be performed and added into the API storage.
On completion the callback
function is called.
callback
is passed undefined
: this indicates the translation was successful and is accessible using the api.fetch
method.callback
is passed an error
: this indicates something went wrong.
The outspace API is unstable, which means that the API fails often.
If that happens, it is okay to api.request
again.api.request('majQa’', callback);
// => undefined
//
// later: the passed callback is called with undefined
// because it was successful.
âš Warning! âš
The API works its magic by teleporting in the various translators when a request
comes in.
This is a very costly action, so it shouldn't be called when a translation is available.
Unfortunately, not everyone reads the manual, so there is a system in place to kick-out bad actors.
If an api.request
is called for text
is available, the API throws an AbusiveClientError
for this call, and every call after that.
Ensure that you never request a translation if something has already been translated.
The free service only provides translations that are currently in the API storage.
Implement a method free(text)
that provides free members with translation that already exist in the API storage.
Ignore the quality and forward any errors thrown by the API.
api.fetch
method (api.fetch
returns a promise
)service.free('jIyaj');
// => Promise<...> resolves "I understand."
service.free("jIyajbe'");
// => Promise<...> rejects Error("Not yet translated")
Implement a method batch([text, text, ...])
for free members that translates an array of text using the free service, returning all the translations, or a single error.
BatchIsEmpty
error if no texts are givenservice.batch(['jIyaj', "majQa'"]);
// => Promise<...> resolves ["I understand.", "Well done!"]
service.batch(['jIyaj', "jIyajbe'"]);
// => Promise<...> rejects new Error("Not yet translated")
service.batch([]);
// => Promise<...> rejects BatchIsEmpty()
Implement a premium user method request(text)
, that requests a translation be added to the API storage.
The request should automatically retry if a failure occurs.
It should perform no more than 3 calls for the same request (don't upset the space translators!!!).
api.request
does not return an error, resolve with undefined
api.request
returns an error, retry at most two timesservice.request("jIyajbe'");
// => Promise<...> resolves (with nothing), can now be retrieved using the fetch API
Implement a premium user method premium(text, quality)
to fetch a translation.
If a translation is NotAvailable
, request the translation and fetch it after its been added to the API storage.
The method should only return the translation if it meets a certain quality
threshold.
api.fetch
resolves, check the quality before resolvingapi.fetch
rejects, request the translation insteadapi.request
rejects, forward the errorservice.premium("jIyajbe'", 100);
// => Promise<...> resolves "I don't understand."
service.premium("'arlogh Qoylu'pu'?", 100);
// => Promise<...> rejects QualityThresholdNotMet()
service.premium("'arlogh Qoylu'pu'?", 40);
// => Promise<...> resolves "What time is it?"
N.B.
The correct translation of 'arlogh Qoylu'pu'?
is How many times has it been heard?.
Sign up to Exercism to learn and master JavaScript with 33 concepts, 148 exercises, and real human mentoring, all for free.