Nghĩa là gì

Engineering Blog | Aloteen


Pinky Swear

Like clockwork the Learning ES6 series continues on, looking at promises. It will be the first feature we’ve looked at in this series that really is more than syntactic sugar. But promises aren’t entirely new to JavaScript. They’ve existed for quite some time in helper libraries. ECMAScript 6 now brings native promise support to JavaScript via the Promise API. Let’s jump right in!

Bạn đang xem: pledge là gì


A promise represents the eventual result of an asynchronous operation. Instead of registering a callback in the call to an async function, the function returns a promise. The caller registers callbacks with the promise to receive either a promise’s eventual value from the async operation or the reason why the promise cannot be fulfilled.

// Creating a promise wrapper for setTimeout function wait(delay = 0) { return new Promise((resolve, reject) => { setTimeout(resolve, delay); }); } // Using a promise wait(3000) .then(() => {‘3 seconds have passed!’); return wait(2000); }) .then(() => {‘5 seconds have passed!’); x++; // ReferenceError triggers `catch` }) .catch(error => { // output: ReferenceError; }) .then(() => { // simulate `finally` clause‘clean up’); });

Did you notice the use of default parameters and arrow functions too? If you’re unfamiliar with those ES6 features, you should check out the articles detailing how they work. Interested in learning more about ES6 promises? Clone the Learning ES6 Github repo and take a look at the promises code examples page showing off the features in greater detail.

Well you’ve come this far. You might as well keep going!

Asynchronous programming background

Because JavaScript originated as a programming language for the web, asynchronous programming has existed in it since its inception. Program execution couldn’t wait for user interactions (such as clicks and key presses) before continuing like you would see in console applications. Asynchronous programming in JavaScript provides mechanisms for an application to be notified when events it cares about have just happened.

Event handlers

Event handlers are what I call the first generation of asynchronous programming in JavaScript. You simply assigned a function to an event property and it was called whenever that event happened. Here’s the event handler way of making an XHR request.

var url = ‘/json/data.json’, request = new XMLHttpRequest();‘GET’, url); = function() { if (request.status === 200) { try { var responseJson = aloteen.vne(request.responseText); // do something with daa } catch (e) { aloteen.vnr(e); } } else { aloteen.vnr(‘request failed!’); } }; aloteen.vnror = function(e) { aloteen.vnr(e); } try {; } catch (e) { aloteen.vnr(e); }

This style is so old that it may actually be unfamiliar for some JavaScript developers. Most developers nowadays are used to callbacks.


JavaScript libraries, like jQuery, aimed to ease development pains by hiding event handlers behind functions that called a specified callback function when the event was trigged. This programming style of using callbacks is also called continuation-passing style (CPS) because the next step (the continuation) is explicitly passed in as a parameter:

function fetch(url, callback) { var request = new XMLHttpRequest();‘GET’, url); = function() { var data, error; if (reques.status === 200) { data = aloteen.vnonseText; } else { error = new Error(‘request failed!’); } callback({data:data, error:error}); }; aloteen.vnror = function(e) { callback({error: e}); } try {; } catch (e) { callback({error: e}); } } fetch(‘/json/data.json’, function(responseObj) { if (!responseObj.error) { try {‘data!’, aloteen.vne(; } catch (e) { aloteen.vnr(e); } } else { aloteen.vnr(responseObj.error);} });

The callback pattern, while more convenient to use than event handlers, still had several drawbacks. The first is apparent in the example. The callback function has two ways of handling errors: if-else on the returned data and try-catch around any operations within the function.

Secondly, callback functions proved to be untenable when developers had callbacks within callback within callbacks. This affectionately became known as callback hell. Let’s say for example after you retrieved /json/ you needed to make another fetch request based on the returned data from the first request:

fetch(‘/json/data.json’, function(responseObj) { if (!responseObj.error) { try { var data = aloteen.vne(;‘main data’, data); // now call `fetch` again to retrieve new data // based on the response data fetch(data.url, function(responseObjInner) { if (!responseObjInner.error) {‘inner data’,; } else { aloteen.vnr(responseObjInner.error);} }); } catch (e) { aloteen.vnr(e); } } else { aloteen.vnr(responseObj.error);} });

It’s already a mess and we’re only two levels deep without any real implementation!

Attempting to manage multiple active callbacks is also pretty complicated. Imagine you wanted to fire off multiple fetch requests simultaneously and then you wanted to process the results when they are all done? Or what if you wanted to time out a fetch request after it had run for more than 10 seconds? It’s doable, but challenging with callbacks.

Enter promises.


Promises ushered in the 3rd generation of asynchronous programming. A promise represents the eventual result of an asynchronous operation. Instead of registering a callback in the call to an async function (such as fetch), the function returns a promise. The caller then registers callbacks with the promise (not the function) to receive either the promise’s eventual value from the async operation or the reason why the promise could not be fulfilled.

ECMAScript 6 brings native promise support to JavaScript following the Promise/A+ standard. Promises have actually existed for quite some time in JavaScript as external libraries. The following libraries also follow the Promise/A+ standard:

  • by Stefan Penner
  • ES6 Promise Polyfill by Jake Archibald
  • Native Promise Only by Kyle Simpson
  • Q.Promise by Kris Kowal
  • Lie by Calvin Metcalf
  • ES6 Shim by Paul Miller
  • when by cujoJS

The new Fetch API provides a fetch method that is an updated and promise-backed version of XMLHttpRequest. In fact, moving forward, all asynchronous APIs will be promise-backed. If we wanted to turn our callback-style fetch function from before to be promised-backed, we could create a poor man’s version of the new Fetch API:

function fetch(url) { // return a Promise object return new Promise((resolve, reject) => { let request = new XMLHttpRequest();‘GET’, url); = function() { if (request.status === 200) { // fulfill the promise resolve(request.responseText); } else { // reject the promise reject(new Error(‘request failed!’)); } };; }); } fetch(‘/json/data.json’) .then(response => { let data = aloteen.vne(response.text);‘main data’, data); // now call `fetch` again to retrieve new data // based on the response data return fetch(data.url); }) .then(response => {‘inner data’, response); }) .catch(e => { // catching all failures! aloteen.vnr(e); });

Much nicer to use, eh? Don’t worry if you don’t understand everything going on. We’re going to spend the rest of our time breaking apart this example. You’ll notice that callbacks still exist, but they are attached to the promise and not the function itself. A different promise callback is called depending on the outcome.

The error callback (catch()) is particularly convenient for two reasons:

  1. It’s a single style of handling errors. Remember the the if-else and all the try-catch blocks in the callback-style approach? try-catch isn’t needed in creating a Promise nor in handling one.
  2. You can handle the errors from executing the async request (XHR in this case) or errors introduced by handling the async request (in then() callbacks) from a single location (catch() callback).

Point #2 is one of the big reasons why jQuery’s Deferred object is not Promise/A+. Instead, errors in handling the async request that are uncaught are bubbled up to aloteen.vnr. However, jQuery 3’s Deferred object will be Promise/A+.

By the way, if you’re interested in a polyfill for Fetch API, check out Github’s whatwg-fetch library.

Reactive programming

Reactive programming (built on top of functional programming) is positioning itself as the next generation of asynchronous programming. Reactive extensions implements reactive programming in JavaScript. From the README:

One question you may ask yourself, is why RxJS? What about Promises? Promises are good for solving asynchronous operations such as querying a service with an XMLHttpRequest, where the expected behavior is one value and then completion. The Reactive Extensions for JavaScript unifies both the world of Promises, callbacks as well as evented data such as DOM Input, Web Workers, Web Sockets. Once we have unified these concepts, this enables rich composition.

But let’s not get ahead of ourselves here. Let’s stick to learning about promises.

Making a promise

A promise can be in one of the following three states:

  • Unsettled/pending – the promise’s async operation has yet to compute its result
  • Settled: fulfilled – the promise’s async operation has completed successfully and computed a result to return
  • Settled: rejected – the promise’s async operation did not complete successfully, most likely due to an error

A promise is settled (the async operation has completed) if it is either fulfilled or rejected. A promise can only transition from unsettled to settled one time and it remains settled. Attempting to settle an already settled promise does nothing. Here’s a visualization of the (short) lifecycle of a promise from Axel Rauschmayer:

Let’s take a look again at the Promise constructor in our promised-back fetch function:

function fetch(url) { // return a Promise object return new Promise((resolve, reject) => { let request = new XMLHttpRequest();‘GET’, url); = function() { if (request.status === 200) { // fulfill the promise resolve(request.responseText); } else { // reject the promise reject(new Error(‘request failed!’)); } };; }); }

The function passed to the Promise constructor is called the executor. If the async function’s computation went well, the executor sends the result via resolve(). This typically will fulfill the promise. However, if you resolve the promise with another Promise (more on this later), the promise may not be fulfilled.

If an error happened or the async operation failed, the executor informs the user of the promise via reject(). This always rejects the promise. Like throw in plain old JavaScript, it’s suggested that you call reject() with an Error object. On of the benefits of passing along an Error object is that it will capture a stack trace, which makes debugging much easier.

If an error is thrown within the executor, the promise’s reject() handler is automatically called.

new Promise((resolve, reject) => { throw new Error(‘Error!’); });

So we’re intentionally throwing an error within the executor, but lets pretend that this error happened while performing the async operation (like making an XHR request). There is an implicit try-catch inside of every executor. This means that any errors are caught and passed along to the reject() handler. Basically, the example would be equivalent to:

new Promise((resolve, reject) => { try { throw new Error(‘Error!’); } catch (e) { reject(e); } });

Claiming a promise

Consumers of promises are notified of either fulfillment or rejection by what are called reactions. These are callbacks registered with the then() method on a Promise. From our promised-backed fetch earlier:

Xem thêm: Phần mềm Repack là gì? Hướng dẫn sử dụng và cài đặt phần mềm Repack

fetch(‘/json/data.json’) .then(response => { // handle response data }, error => { // handle errors });

The then() method accepts two arguments:

  1. The first argument is the function to call when the promise is fulfilled. Any additional data related to the async operation (such as the response from the XHR request) is passed into this fulfillment reaction
  2. The second argument is the function to call when the promise is rejected. The rejection reaction can also be passed additional data. As mentioned, this usually is an Error object.

If you are only interested in a fulfillment, you can omit the second parameter to then():

fetch(‘/json/data.json’) .then(response => { // handle response data });

If you’re only interested in a rejection, you can skip the first parameter to then() by passing null:

fetch(‘/json/data.json’) .then(null, e => { // handle errors });

Alternatively, you can use the catch() method which is more succinct:

fetch(‘/json/data.json’) .catch(e => { // handle errors });

The convention is to use then() exclusively for fulfillments and catch() exclusively for errors. This nicely labels the reactions. The advantage of using then() and catch() over the old-generation event handlers and callbacks is that it’s completely clear whether the code is handling success or failure. Many times with callbacks there is a single callback and within it you have to do an if check against any errors.

By the way, if you fail to attach a rejection reaction to a promise and an error does occur, the promise will fail gracefully. The failure will happen silently. The convention is to always attach a rejection reaction to a promise even if all it ends up doing is logging the failure.

One super convenient feature of promises is that there are never any race conditions. It doesn’t matter when you call the then() method of a promise. If you’re passed a Promise that is already settled and then call then(), you will receive the cached settled value immediately. Pretty nice! Speaking of settled promises…

Creating settled promises

Normally you would create an unsettled promise via the Promise constructor. The promise would get settled once the async operation has been successful (fulfilled) or unsuccessful (rejected). These are the examples we’ve just covered. However, you can create “immediately” settled promises in either the fulfilled or rejected state.

Let’s say we wanted to create an “immediately” fulfilled promise:

// aloteen.vnlve() creates a promise // that is “immediately” settled & fulfilled. // You can optionally pass a value aloteen.vnlve(‘Ben’) .then(name => { // output: Ben; });

The aloteen.vnlve() factory method returns an “immediately” fulfilled promise on which we call its then() method to get the passed value. If a rejection reaction were added to this promise, it would never get called because the promise will never be in a rejected state.

One interesting feature with promises is that they are required to always be asynchronous. That’s why I’ve been saying “immediately” fulfilled. Even though there’s no async operation when using aloteen.vnlve the fulfillment reaction is still handled asynchronously because it is added to the execution queue. Any code after the promise will be executed before the output. For instance:

// aloteen.vnlve() creates a promise // that is “immediately” settled & fulfilled. // You can optionally pass a value. aloteen.vnlve(‘Ben’) .then(name => { // output: Ben; }); // Even though the promise is “immediately” // fulfilled, all promises are required to // be asynchronous. Therefore the fulfillment // reaction is added to the execution queue // and the following line executes first.‘this executes before the fulfillment’);

You can also “immediately” reject promises using the aloteen.vnct() factory method. This works exactly like aloteen.vnlve() except that the promise is created in the rejected state.

// aloteen.vnct() creates a promise that // is “immediately” settled & rejected. You // should pass an `Error` object. aloteen.vnct(new Error(‘Pride!’)) .catch(e => { aloteen.vnr(e); }); // Similarly, because promises *must* be // asynchronous, this line will execute first‘this executes before the rejection’);

And just like with aloteen.vnlve(), if a fulfillment reaction (then()) were added to this “immediately” rejected promise, that handler would never be called.

What happens when you pass a Promise to aloteen.vnlve() or aloteen.vnct()? Nothing. The promise is just returned:

let fetchPromise = fetch(‘/json/data.json’); // Fulfilling or rejecting an already existing // promise does nothing. It’s just returned // output: true == fetchPromise); == fetchPromise);

Why in the world would you pass a Promise object to aloteen.vnlve() or aloteen.vnct()? Well it’ll make sense after your learn about thenables.


A thenable as defined by the Promise API spec is any object that has a Promise-style then() method. This means that the method accepts two arguments that are functions (resolve() and reject()). Therefore, a Promise is also a thenable.

If this were C# or Java, there would be an IThenable interface that defined one method called then which accepted two lambda functions. The Promise class would implement the IThenable interface. But because IThenable is an interface, any class could implement it. Although JavaScript doesn’t have interfaces, the concept is still the same:

// Resolving a `thenable` returns a `Promise` // on which you can add `then()` or `catch()` // reactions aloteen.vnlve({ // A `thenable` is an object that // has a Promise-style `then` method. // Using method definition shorthand! then(resolve, reject) { resolve(‘Ben’); } }) .then(name => { // using property value shorthand! // output: {name: ‘Ben’}{name}); });

The thenable object in this example is just a simple object literal (using object method shorthand). It’s not at all like a full-fledged Promise object except for the fact that it has a then() method. It implements the “IThenable” interface.

And thenables are not limited to object literals. Any object that has a Promise-style then() method is a thenable, including the jQuery Deferred object:

var $fetch = function(url) { return aloteen.vnlve($.get(url)); }; $fetch(‘/json/data.json’).then(response => {‘response’, response); });

The return value from $.get(url) is a thenable (a jQuery-style promise). The example calls aloteen.vnlve() on that return value to create an ES6-style Promise. That’s some pretty nice interoperability.

As you might’ve guessed, any thenable can also be converted into a rejected Promise using aloteen.vnct(). When in doubt about whether or not the object you have is an ES6-style Promise, just go ahead and call aloteen.vnlve() or aloteen.vnct() on the object. If the object is already a Promise, nothing will happen to it. Otherwise, you’ll be able to convert a thenable into a Promise.

This allows for chaining of promises to accomplish more complex asynchronous behavior that you could never easily accomplish with callbacks.

Chaining promises

The Promise API functionality we’ve leveraged so far has been great. I would definitely use it over callbacks or event handlers, even if it is only a minor improvement. But promises demonstrate their real power when you leverage their ability to be chained together.

You see, each call to then() or catch() under the hood actually creates and returns another promise. Remember our example from above?

fetch(‘/json/data.json’) .then(response => { var data = aloteen.vne(response);‘main data’, data); // now call `fetch` again to retrieve new data // based on the response data, which returns // a promise return fetch(data.url); }) .then(response => {‘inner data’, response); // an empty fulfilled promise is returned });

Without chaining, the code would look something like this:

let fetchPromise = fetch(‘/json/data.json’); let innerFetchPromise = => { var data = aloteen.vne(response);‘main data’, data); // now call `fetch` again to retrieve new data // based on the response data, which returns // a promise return fetch(data.url); }); => {‘inner data’, response); // an empty fulfilled promise is returned });

And of course that last call to would also return a promise. We just didn’t need to consume it.

Returning values

Another key aspect of promise chaining is the ability pass data from one promise onto the next. When an unsettled promise is created and the async operation is successful, typically a value (such as the XHR response) is passed to resolve() by the executor to fulfill the promise. Well, value passing doesn’t stop there. Promise reactions can continue to pass along values by returning them.

// Create immediately fulfilled promise // that returns ‘Ben’ aloteen.vnlve(‘Ben’) .then(firstName => { // output: Ben; return `${firstName} A.`; }) .then(firstAndMiddle => { // output: Ben A.; return `${firstAndMiddle} Ilegbodu`; }) .then(fullName => { // output: Ben A. Ilegbodu; });

Notice the use of ES6 string interpolation! Of course this is a very contrived example, but passing values can be useful if you need to take the result of a settled promise, process that result and create a new promise from it. If the processing can potentially throw errors, you’ll be able to easily catch those errors along with any other errors happening in the promise chain. You can jump ahead to Error handling if you’re interested.

You’re more likely to want to return a Promise (or thenable) than actual values. More than likely you could do all of your value processing in a single then() reaction. But if you wanted to make sequential async operations (like XHR requests that depend on the response of a previous request), after getting the response of the first operation, you would kick off the next operation based on data from the first and return the second operation’s Promise. We saw an example of this earlier:

Xem thêm: Đôi nét về lệnh ADB mà người dùng Android nên biết

fetch(‘/json/data.json’) .then(response => { var data = aloteen.vne(response);‘main data’, data); // now call `fetch` again to retrieve new data // based on the response data, which returns // a new promise return fetch(data.url); }) .then(response => {‘inner data’, response); });

Like we discussed in the section on Callbacks, the callback version of this code is the makings of callback hell because the call to the second fetch would be in the callback handler of the first. Promises nicely flatten this out with chaining. They also provide a unified location to handle errors.

Error handling

The catch() reaction is the way you handle errors with promises. We learned all about catch() when we learned about claiming promises. Promise chaining now allows you to catch any errors that may occur in a previous then() or catch() reaction.

// Create immediately fulfilled, but // empty promise aloteen.vnlve() .then(() => { // throw an `Error` which should be // caught by `catch()` throw new Error(‘oh no!’); }).catch(e => { // output: ‘oh no!’ error with call // stack info aloteen.vnr(e); });

This sort of thing just wasn’t feasible with callbacks unless you explicitly added a try-catch inside the callback. But what if your rejection reaction itself throws an error? Well you can catch() that too!

// Create immediately fulfilled, but // empty promise aloteen.vnlve() .then(() => { // throw an `Error` which should be // caught by `catch()` throw new Error(‘oh no!’); }) .catch(e => { // output: ‘oh no!’ error with call // stack info aloteen.vnr(e); // throw another `Error` within this // error handler, which can be caught // by a follow-up error handler throw new Error(‘again?!?!’); }) .catch(e => { // output: ‘again?!?!’ error aloteen.vnr(e); });

Interestingly enough, if you decide to return a value in your rejection reaction instead of throwing an Error, it becomes a fulfillment value for the next promise. This allows you to specify default values to use in case of failure without having to break chaining.

fetch(‘/json/bad-data.json’) .catch(() => { // There was an error retrieving data // so just return default data return aloteen.vnngify({name: ‘Ben Ilegbodu’}); }) .then(response => { // at this point we should always have // valid data regardless of if the `fetch` // was successful // output: {name: ‘Ben Ilegbodu’}; });

Pretty helpful, huh? But wait, there’s more! The catch() does not need to immediately follow the promise that caused the error. Errors are passed down the promise chain until a catch() reaction is found. If no reject reaction is found, the error fails silently.

// Create immediately rejected and empty // promise aloteen.vnct(new Error(‘FAIL!’)) .then(() => { // because the promise is rejected, // this fulfillment reaction is never called }) .then(() => { // neither is this one }) .catch(e => { // instead this reject reaction is called // to handle the rejection that happened further // up the chain // output: ‘FAIL!’ error aloteen.vnr(e); });

Even more helpful! If you stick a catch() at the end of your promise chain it’ll always get called no matter where an error occurs. Even if all the catch() does is log the error and rethrow, it’s a good practice to perform.

Promise composition

Up until this point, we have composed promises using sequential chaining. The next promise doesn’t get handled until the previous promise is settled (either fulfilled or rejected). However, there are times when you will want to track multiple async operations at the same time in order to determine what to do next.

ECMAScript 6 provides additional ways of composing promises via the and helpers.


Let’s say you have multiple async requests you want to fire off in parallel and then once they are done you want to use their results to do some additional processing. In the callback world you would have to maintain a variable that keeps track of which requests have returned and which haven’t. You will also need a data structure that would contain the results (and potentially in the order in which the requests were called). While this is doable with callbacks, it’s unnecessarily complex and error-prone, especially when you also need to do error handling.

The method makes this significantly easier. It takes an array of promises as a parameter and returns a Promise that will be fulfilled with an array of response values only when all of the promises are fulfilled.

// Return a promise that is only fulfilled once // all of the url fetch requests are fulfilled // via function fetchAll(…urls) { // Use rest parameter to aggregate URLs // into an array return // map the array of urls into an array // of `fetch` promises ); } // Make an XHR request for each URL and // process the results once they’ve *all* // completed fetchAll( ‘/json/data.json’, ‘/json/data2.json’, ‘/json/data3.json’, ‘/json/data4.json’, ‘/json/data5.json’ ) .then(responses => { // `responses` is the array of response // data // output: 5; // more processing of results });

Much easier, huh? Much more readable too. The example also leverages rest parameters. I like to think of it as somewhat analogous to aloteen.vny, which returns true (success) if all of the elements of the array pass the test implemented in the callback.

If any of the promises are rejected (i.e. fail), then the aggregator Promise from also is rejected. You can use the catch() reaction to catch these failures.

// Make an XHR request for each URL and // process the results once they’ve *all* // completed fetchAll( ‘/json/data.json’, ‘/json/data2.json’, ‘/json/data3.json’, ‘/json/data4.json’, ‘/json/data5.json’ ) .then(responses => { // `responses` is the array of response // data // output: 5; // more processing of results }) .catch(e => { // one or more of the requests failed // or there was an error in `then()` aloteen.vnr(e); });

Imagine trying to replicate this level of error handling with callbacks! It’s worth mentioning that all of the promises ultimately settle even if one of them settles in a rejected state while some are still pending. They won’t get cancelled. You should also know that also accepts non-Promise objects. Any thenable or non-Promise objects are auto-resolved using aloteen.vnlve.


I find to be a little less useful than It operates on an array of Promise objects and returns a promise as well. The difference is that the resultant promise settles based on the first settlement of the array of promises. It’s a race! If the first promise to settle in the array of promises is fulfilled (aka a success), then the resultant promise will be fulfilled. However, if the first settled promise is rejected (aka a failure), then the resultant promise will be rejected as well.

How it works is a bit weird, and best explained with a use-case. The best one I could find for is timing out an async operation. Let’s say you want to make a promise-based fetch, but that request could take a long time and you want to time out after 5 seconds if the request has yet to return a response. Using we can combine our promise-based fetch with our promise-based wait from earlier. If the wait wins the “race,” then a timeout has occurred and we can handle the error appropriately.

// Extend the promise-based `wait` by throwing // an Error if the delay is successful function timeout(delay=3000) { return wait(delay).then(() => { throw new Error(‘Timed out!’); }); } // Return a promise that will be fulfilled if // the fetch is fulfilled before the timeout // is rejected. function fetchWithTimeout(url, delay=3000) { // construct an array to pass to `Promise.race` return[ fetch(url), timeout(delay) ]); } // Make an XHR request for the URL that has to // return a response *before* the 5 ms timeout // happens fetchWithTimeout(‘/json/data.json’, 5) .then(response => { // successful response before the 5 ms timeout‘successful response’, response) }) .catch(e => { // Either the timeout occurred or some other error. // Would need to check the method or use a custom // `Error` subclass in `timeout` aloteen.vnr(‘request error’, e); });

At first, it may seem weird to throw an Error in timeout when the delay is successful, but it makes sense. We want it to be an error if the timeout actually happens. That way we can distinguish success from failure in the “race”. When timeout settles, it will be a rejection. When fetch settles, it will be a fulfillment. Therefore, whichever one settles first, will win the “race” and we can react appropriately. The then reaction will retrieve the success response and the catch reaction will handle the timeout.

As mentioned in the comment, if you really wanted timeout to be useful it would return a custom Error object so that callers could just type check the Error object they receive instead of having to compare error messages. This is because if the fetch fails for some reason, it will also go to the catch reaction. can work with an array of any size, but I can’t really think of a realistic use case where you’d want to fire off multiple async operations, only caring about the first one that returns. But I’m sure there is one.

Inheriting from Promise

Just like with other built-in types, the Promise class can be subclassed to create your own more specific promise objects. Let’s say you don’t like the names then() and catch() and want to use done() and fail() instead (to be more like jQuery). You could subclass Promise to add in these methods.

class JPromise extends Promise { // use the default constructor. no need to // override it // callback registered via `done` will only // be called when the `Promise` is fulfilled done(resolve) { // intentionally omitting the `reject` callback // that’s also passed to `then` return; } // `fail` is just a name wrapper around `catch` fail(reject) { return aloteen.vnh(reject); } } aloteen.vnlve(‘Ben Ilegbodu’) .done(name => {‘using done instead of then!’, name); throw new Error(‘FAIL for fun!’) }) .fail(e => { aloteen.vnr(‘sad face’, e); });

You may have also noticed the use of aloteen.vnlve instead of just aloteen.vnlve to create the promise. resolve and reject are also inherited so when we call them on JPromise, we get back a JPromise object instead of a generic Promise object.

Wrapping things up

We’re entering the home stretch now!

While the Promise API based on the Promises/A+ standard is crazy powerful, it’s still lacking some useful functionality that exist in some of our existing promise libraries.

The first omission is the ability to cancel a Promise. This could come in handy when using or If one promise’s completion causes the result of others to no longer matter, it’d be nice to be able to cancel them. The cancellation spec is already under development for Promises/A+.

The second omission is the ability to query the progress of a Promise. Imagine making a fetch call of a 100MB file. Being a able to display a progress indicator would be pretty helpful. Thankfully, the progress spec too is under development for Promises/A+.

Promises are good for async operations that happen one time and then they’re done. You shouldn’t use promises for recurring events (such as clicks, key presses, etc.). If you want an alternative to normal event handling for recurring events, try out reactive programming in JavaScript.

JavaScript engine support

According to the ECMAScript 6 Compatibility table all major JavaScript engines (transpilers, browsers and servers) support the Promise API. Some don’t support 100% of the functionality, but the missing pieces most likely won’t be features you’ll be leveraging. The most notable is that Traceur is missing support for generic iterables with and

If you need support for Promise in an older browser, however, check out the es6-promise polyfill or just use core-js to get all of the ES6+ polyfills.

Additional resources

As always, you can check out the Learning ES6 examples page for the Learning ES6 Github repo where you will find all of the code used in this article running natively in the browser.

I’ve got two great web tools for you to play around with ES6 Promises. First there are the ES6 Katas that you’ve come to know and love. But there’s also Promisees: A Visualization Playground for Promises by Nicolas Bevacqua. It’s pretty cool!

Since promises aren’t new to JavaScript (just the native Promise API included with ES6), there are a lot of books and articles covering it. Here’s a smattering:

  • Promises for asynchronous programming in Exploring ES6 by Axel Rauschmayer
  • Promises in Understanding ECMAScript 6 by Nicholas C. Zakas
  • JavaScript Promises by Jake Archibald
  • Coming from jQuery in q by Kris Kowal
  • Asynchronous Programming in Exploring ES6 by Axel Rauschmayer
  • Promise Anti-patterns by Tao of Code
  • Promises/A+ specification

Coming up next…

Wow! That was a meaty one wasn’t it? We’re working our way to be able to have a meaningful conversation about generators. Let’s talk about the new collections added to ES6 next. Until then…


This Learning ES6 series is actually a cross-posting of a series with the same name on my personal blog, The content is pretty much the exact same except that this series will have additional information on how we are specifically leveraging ES6 here in Eventbrite Engineering when applicable.

We are just beginning to use native promises with the whatwg-fetch and es6-promise polyfills so that we do not need to use $.ajax() in our new React apps. I’ll also be tackling the features in a different order than I did in my personal blog. The promises blog post can be found here.

Xem thêm: Liên kết thương hiệu (Brand Association) là gì? | Aloteen

0 ( 0 bình chọn )

Ý kiến bạn đọc (0)

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Bài viết liên quan

Kết nối với chúng tôi

Xem nhiều

Chủ đề

Bài viết mới

Xem thêm