{"version":3,"sources":["webpack:///path---blog-extending-promise-cf24dc289c51dfb31cf2.js","webpack:///./.cache/json/blog-extending-promise.json"],"names":["webpackJsonp","364","module","exports","data","site","siteMetadata","title","author","markdownRemark","id","html","frontmatter","date","pathContext","slug","previous","fields","next"],"mappings":"AAAAA,cAAc,iBAERC,IACA,SAAUC,EAAQC,GCHxBD,EAAAC,SAAkBC,MAAQC,MAAQC,cAAgBC,MAAA,eAAAC,OAAA,kBAAiDC,gBAAmBC,GAAA,gHAAAC,KAAA;AAAik7CC,aAA0VL,MAAA,oBAAAM,KAAA,uBAAyDC,aAAgBC,KAAA,2BAAAC,UAA8CC,QAAUF,KAAA,sBAA4BH,aAAgBL,MAAA,kBAAyBW,MAASD,QAAUF,KAAA,wBAA8BH,aAAgBL,MAAA","file":"path---blog-extending-promise-cf24dc289c51dfb31cf2.js","sourcesContent":["webpackJsonp([230700223712971],{\n\n/***/ 364:\n/***/ (function(module, exports) {\n\n\tmodule.exports = {\"data\":{\"site\":{\"siteMetadata\":{\"title\":\"Valencik.com\",\"author\":\"K.J. Valencik\"}},\"markdownRemark\":{\"id\":\"/home/kvalencik/git/valencik.com/src/pages/blog/extending-promise/index.md absPath of file >>> MarkdownRemark\",\"html\":\"

Promise was added to javascript in the ECMAScript\\n2015 (ES6) standard. If you haven’t had a chance to use promises, I\\nrecommend the MDN guide on using promises. One of the neat\\nthings about promises is that they are designed to be\\nextensible. When calling methods that construct new promises, they use\\nthis.constructor.

\\n

We can verify this by checking the class of the new promise.

\\n
\\n
class MyPromise extends Promise {}\\n\\nconst p0 = MyPromise.resolve();\\nconst p1 = p.then(() => {});\\n\\nassert(p0 instanceof MyPromise);\\nassert(p1 instanceof MyPromise);\\n
\\n
\\n

We’ve created our own sub-class of Promise that we can call\\ncombinators (e.g., then) on and it returns an instance of that\\nsub-class!

\\n

Our first combinator

\\n

This is where it gets fun. What if we want to extend the set of built-in\\ncombinators to build a promise utility belt like Bluebird? Let’s\\nstart with something simple. We want to add a simple method (log) that logs\\nthe value and passes the result unmodified.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tlog(log = console.log) {\\n\\t\\treturn this.then(value => {\\n\\t\\t\\tlog(value);\\n\\n\\t\\t\\treturn value;\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

Wait, this.then? What’s this about? Since log is a method on\\nPromiseCombinator.prototype it can reference the\\npromise as this to start chaining. Let’s break this code down.

\\n

We define a sub-class of Promise called PromiseCombinator.

\\n
\\n
class PromiseCombinator extends Promise {\\n
\\n
\\n

We define a method on that class named log. It accepts a single argument named\\nlog with a default value of console.log.

\\n
\\n
\\tlog(log = console.log) {\\n
\\n
\\n

Next, we want the value the promise resolves to and not just the promise. We use\\n.then to chain a callback and add our log. We also return the original value\\nto ensure that it doesn’t get dropped.

\\n
\\n
return this.then(value => {\\n\\tlog(value);\\n\\n\\treturn value;\\n});\\n
\\n
\\n

Finally, let’s see how it can be used.

\\n
\\n
PromiseCombinator.resolve(\\\"Hello, World!\\\")\\n\\t.log()\\n\\t.then(value => assert.equal(value, \\\"Hello, World!\\\"));\\n
\\n
\\n
\\n
Hello, World!
\\n
\\n

Something useful

\\n

Creating a log method was a good learning exercise, but isn’t especially\\nuseful. A common task is to perform an action on a collection of values, e.g.\\nmap and filter. Array.prototype provides a good\\ntemplate for implementation.

\\n

Map

\\n

Array.prototype.map accepts a method that will be called for each\\nitem in the collection and produces a new Array with the results. The method\\nreceives 3 arguments: the item, the position in the array, and the full array.

\\n

Let’s create a version of map that executes an asynchronous task for each item\\nconcurrently. This is where Promise.all comes in handy.\\nPromise.all accepts a collection of promises. It returns a promise that\\nresolves to a collection of values from each of those promises.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

Shouldn’t we use PromiseCombinator.all? Won’t this cause us to return an\\ninstance of Promise instead of PromiseCombinator? It turns out, it doesn’t\\nmatter because the then ensures we always return an instance of\\nthis.constructor.

\\n

The call to the built-in arr.map creates an array of promises and the call to\\nPromise.all waits for those promises to resolve.

\\n
\\n
const promises = arr.map(callback);\\n\\nreturn Promise.all(promises);\\n
\\n
\\n

Filter

\\n

Array.prototype.filter accepts a method called a\\npredicate. A predicate is a function that either evaluates to\\ntrue or false. Similar to map, the predicate is called for each item in the\\ncollection and receives the item, the index and the array. The result of\\nfilter is a new array that only contains the items where the predicate\\nevaluated to a truthy value.

\\n

Once we’ve implemented an asynchronous map, an asynchronous filter follows\\nnaturally. We can use map to handle a predicate that returns a promise.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n\\n\\tfilter(predicate) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\treturn this.map(predicate).then(values =>\\n\\t\\t\\t\\tarr.filter((_, i) => values[i])\\n\\t\\t\\t);\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

First, let’s wait for the promise to resolve and then let’s use map to execute\\nour predicate on each of the values. The order of these calls does not matter\\nand they can be inverted, but later we will need a copy of the original array.

\\n
\\n
return this.then(arr => {\\n\\treturn this.map(predicate).then(values =>\\n\\n// also acceptable\\nreturn this.map(predicate).then(values => {\\n\\treturn this.then(arr =>\\n
\\n
\\n

Lastly, we can perform a synchronous filter on the original array using the\\nresults from the map.

\\n
\\n
arr.filter((_, i) => values[i]);\\n
\\n
\\n

Putting it all together, we can produce a promise chain that filters to even\\nnumbers and multiplies them by 2.

\\n
\\n
PromiseCombinator.resolve([1, 2, 3, 4])\\n\\t// Return a promise from the predicate for demonstration purposes\\n\\t.filter(x => Promise.resolve(x % 2))\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n

Going further

\\n

Now we can chain multiple methods together, but the nested calls in filter are\\ndifficult to follow. Can we do better? Async/Await is a feature added\\nin ECMAScript 2017 (ES8). It utilizes the await operator to\\nwrite asynchronous code more like synchronous code. We can re-write our filter\\nmethod async.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n\\n\\tfilter(predicate) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tconst values = await this.map(predicate);\\n\\n\\t\\t\\treturn arr.filter((_, i) => values[i]);\\n\\t\\t});\\n\\t}\\n}\\n\\nPromiseCombinator.resolve([1, 2, 3, 4])\\n\\t.filter(x => x % 2)\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n

The async operator will ensure that the method always returns a promise and\\nenables the use of the await operator.

\\n
\\n
\\t\\treturn this.then(async arr => {\\n
\\n
\\n

The await operator will defer execution of the block until a value is yielded\\nfrom the promise.

\\n
\\n
\\t\\t\\tconst values = await this.map(predicate);\\n
\\n
\\n

Great! But, if we can define a method as async, why use .then at all in our\\nmethods? Can’t we define map and filter async as well?

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tasync map(callback) {\\n\\t\\tconst arr = await this;\\n\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\treturn Promise.all(promises);\\n\\t}\\n\\n\\tasync filter(predicate) {\\n\\t\\tconst arr = await this;\\n\\t\\tconst values = await this.map(predicate);\\n\\n\\t\\treturn arr.filter((_, i) => values[i]);\\n\\t}\\n}\\n\\nPromiseCombinator.resolve([1, 2, 3, 4])\\n\\t.filter(x => x % 2)\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n
\\n
TypeError: PromiseCombinator.resolve(...).filter(...).map is not a function
\\n
\\n

We can, but it turns out it breaks chaining. Any method defined as async\\nwill always return a Promise even if a sub-class is returned inside.

\\n

Series

\\n

So far, we’ve only worked with unbounded parallelism. What if we wanted to\\nimplement a forEach method that operated serially? I.e., we call a method for\\neach item in a collection, waiting for the result to resolve before continuing\\nto the next item.

\\n

The await will defer execution of the remainder of the block until the promise\\nhas resolved. If it is called in a loop, the loop will pause on each iteration\\nto await the promise. We can combine this with\\nArray.prototype.entries—a method of enumerating the indices\\nand values of an Array—and have a fairly succinct way of expressing a serial\\nforEach.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tforEach(callback) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tfor (const [index, value] of arr.entries()) {\\n\\t\\t\\t\\tawait Promise.resolve(callback(value, index, arr));\\n\\t\\t\\t}\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

The only trick here is that callback may or may not return a promise. Unlike\\nPromise.all, the await operator requires a promise. We can use\\nPromise.resolve to wrap the result in a promise if it isn’t\\na promise already.

\\n

Putting it all together

\\n

One last improvement we can make to ergonomics is to add some static\\nmethods to remove redundant calls to PromiseCombinator.resolve.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tstatic map(value, callback) {\\n\\t\\treturn PromiseCombinator.resolve(value).map(callback);\\n\\t}\\n\\n\\tstatic filter(value, predicate) {\\n\\t\\treturn PromiseCombinator.resolve(value).filter(predicate);\\n\\t}\\n\\n\\tstatic forEach(value, callback) {\\n\\t\\treturn PromiseCombinator.resolve(value).forEach(callback);\\n\\t}\\n\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n\\n\\tfilter(predicate) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tconst values = await this.map(predicate);\\n\\n\\t\\t\\treturn arr.filter((_, i) => values[i]);\\n\\t\\t});\\n\\t}\\n\\n\\tforEach(callback) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tfor (const [index, value] of arr.entries()) {\\n\\t\\t\\t\\tawait Promise.resolve(callback(value, index, arr));\\n\\t\\t\\t}\\n\\t\\t});\\n\\t}\\n}\\n\\nPromiseCombinator.filter([1, 2, 3, 4], x => x % 2)\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n

Shameless plug

\\n

It was fun learning about promises and how they can be extended with more\\npowerful combinators. For a more complete collection of combinators, you may be\\ninterested in my library extends-promise.

\",\"frontmatter\":{\"title\":\"Extending Promise\",\"date\":\"February 16, 2018\"}}},\"pathContext\":{\"slug\":\"/blog/extending-promise/\",\"previous\":{\"fields\":{\"slug\":\"/blog/hello-world/\"},\"frontmatter\":{\"title\":\"Hello, World!\"}},\"next\":{\"fields\":{\"slug\":\"/blog/rust-overflow/\"},\"frontmatter\":{\"title\":\"Radians and Rust Integer Overflow\"}}}}\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// path---blog-extending-promise-cf24dc289c51dfb31cf2.js","module.exports = {\"data\":{\"site\":{\"siteMetadata\":{\"title\":\"Valencik.com\",\"author\":\"K.J. Valencik\"}},\"markdownRemark\":{\"id\":\"/home/kvalencik/git/valencik.com/src/pages/blog/extending-promise/index.md absPath of file >>> MarkdownRemark\",\"html\":\"

Promise was added to javascript in the ECMAScript\\n2015 (ES6) standard. If you haven’t had a chance to use promises, I\\nrecommend the MDN guide on using promises. One of the neat\\nthings about promises is that they are designed to be\\nextensible. When calling methods that construct new promises, they use\\nthis.constructor.

\\n

We can verify this by checking the class of the new promise.

\\n
\\n
class MyPromise extends Promise {}\\n\\nconst p0 = MyPromise.resolve();\\nconst p1 = p.then(() => {});\\n\\nassert(p0 instanceof MyPromise);\\nassert(p1 instanceof MyPromise);\\n
\\n
\\n

We’ve created our own sub-class of Promise that we can call\\ncombinators (e.g., then) on and it returns an instance of that\\nsub-class!

\\n

Our first combinator

\\n

This is where it gets fun. What if we want to extend the set of built-in\\ncombinators to build a promise utility belt like Bluebird? Let’s\\nstart with something simple. We want to add a simple method (log) that logs\\nthe value and passes the result unmodified.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tlog(log = console.log) {\\n\\t\\treturn this.then(value => {\\n\\t\\t\\tlog(value);\\n\\n\\t\\t\\treturn value;\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

Wait, this.then? What’s this about? Since log is a method on\\nPromiseCombinator.prototype it can reference the\\npromise as this to start chaining. Let’s break this code down.

\\n

We define a sub-class of Promise called PromiseCombinator.

\\n
\\n
class PromiseCombinator extends Promise {\\n
\\n
\\n

We define a method on that class named log. It accepts a single argument named\\nlog with a default value of console.log.

\\n
\\n
\\tlog(log = console.log) {\\n
\\n
\\n

Next, we want the value the promise resolves to and not just the promise. We use\\n.then to chain a callback and add our log. We also return the original value\\nto ensure that it doesn’t get dropped.

\\n
\\n
return this.then(value => {\\n\\tlog(value);\\n\\n\\treturn value;\\n});\\n
\\n
\\n

Finally, let’s see how it can be used.

\\n
\\n
PromiseCombinator.resolve(\\\"Hello, World!\\\")\\n\\t.log()\\n\\t.then(value => assert.equal(value, \\\"Hello, World!\\\"));\\n
\\n
\\n
\\n
Hello, World!
\\n
\\n

Something useful

\\n

Creating a log method was a good learning exercise, but isn’t especially\\nuseful. A common task is to perform an action on a collection of values, e.g.\\nmap and filter. Array.prototype provides a good\\ntemplate for implementation.

\\n

Map

\\n

Array.prototype.map accepts a method that will be called for each\\nitem in the collection and produces a new Array with the results. The method\\nreceives 3 arguments: the item, the position in the array, and the full array.

\\n

Let’s create a version of map that executes an asynchronous task for each item\\nconcurrently. This is where Promise.all comes in handy.\\nPromise.all accepts a collection of promises. It returns a promise that\\nresolves to a collection of values from each of those promises.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

Shouldn’t we use PromiseCombinator.all? Won’t this cause us to return an\\ninstance of Promise instead of PromiseCombinator? It turns out, it doesn’t\\nmatter because the then ensures we always return an instance of\\nthis.constructor.

\\n

The call to the built-in arr.map creates an array of promises and the call to\\nPromise.all waits for those promises to resolve.

\\n
\\n
const promises = arr.map(callback);\\n\\nreturn Promise.all(promises);\\n
\\n
\\n

Filter

\\n

Array.prototype.filter accepts a method called a\\npredicate. A predicate is a function that either evaluates to\\ntrue or false. Similar to map, the predicate is called for each item in the\\ncollection and receives the item, the index and the array. The result of\\nfilter is a new array that only contains the items where the predicate\\nevaluated to a truthy value.

\\n

Once we’ve implemented an asynchronous map, an asynchronous filter follows\\nnaturally. We can use map to handle a predicate that returns a promise.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n\\n\\tfilter(predicate) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\treturn this.map(predicate).then(values =>\\n\\t\\t\\t\\tarr.filter((_, i) => values[i])\\n\\t\\t\\t);\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

First, let’s wait for the promise to resolve and then let’s use map to execute\\nour predicate on each of the values. The order of these calls does not matter\\nand they can be inverted, but later we will need a copy of the original array.

\\n
\\n
return this.then(arr => {\\n\\treturn this.map(predicate).then(values =>\\n\\n// also acceptable\\nreturn this.map(predicate).then(values => {\\n\\treturn this.then(arr =>\\n
\\n
\\n

Lastly, we can perform a synchronous filter on the original array using the\\nresults from the map.

\\n
\\n
arr.filter((_, i) => values[i]);\\n
\\n
\\n

Putting it all together, we can produce a promise chain that filters to even\\nnumbers and multiplies them by 2.

\\n
\\n
PromiseCombinator.resolve([1, 2, 3, 4])\\n\\t// Return a promise from the predicate for demonstration purposes\\n\\t.filter(x => Promise.resolve(x % 2))\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n

Going further

\\n

Now we can chain multiple methods together, but the nested calls in filter are\\ndifficult to follow. Can we do better? Async/Await is a feature added\\nin ECMAScript 2017 (ES8). It utilizes the await operator to\\nwrite asynchronous code more like synchronous code. We can re-write our filter\\nmethod async.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n\\n\\tfilter(predicate) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tconst values = await this.map(predicate);\\n\\n\\t\\t\\treturn arr.filter((_, i) => values[i]);\\n\\t\\t});\\n\\t}\\n}\\n\\nPromiseCombinator.resolve([1, 2, 3, 4])\\n\\t.filter(x => x % 2)\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n

The async operator will ensure that the method always returns a promise and\\nenables the use of the await operator.

\\n
\\n
\\t\\treturn this.then(async arr => {\\n
\\n
\\n

The await operator will defer execution of the block until a value is yielded\\nfrom the promise.

\\n
\\n
\\t\\t\\tconst values = await this.map(predicate);\\n
\\n
\\n

Great! But, if we can define a method as async, why use .then at all in our\\nmethods? Can’t we define map and filter async as well?

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tasync map(callback) {\\n\\t\\tconst arr = await this;\\n\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\treturn Promise.all(promises);\\n\\t}\\n\\n\\tasync filter(predicate) {\\n\\t\\tconst arr = await this;\\n\\t\\tconst values = await this.map(predicate);\\n\\n\\t\\treturn arr.filter((_, i) => values[i]);\\n\\t}\\n}\\n\\nPromiseCombinator.resolve([1, 2, 3, 4])\\n\\t.filter(x => x % 2)\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n
\\n
TypeError: PromiseCombinator.resolve(...).filter(...).map is not a function
\\n
\\n

We can, but it turns out it breaks chaining. Any method defined as async\\nwill always return a Promise even if a sub-class is returned inside.

\\n

Series

\\n

So far, we’ve only worked with unbounded parallelism. What if we wanted to\\nimplement a forEach method that operated serially? I.e., we call a method for\\neach item in a collection, waiting for the result to resolve before continuing\\nto the next item.

\\n

The await will defer execution of the remainder of the block until the promise\\nhas resolved. If it is called in a loop, the loop will pause on each iteration\\nto await the promise. We can combine this with\\nArray.prototype.entries—a method of enumerating the indices\\nand values of an Array—and have a fairly succinct way of expressing a serial\\nforEach.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tforEach(callback) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tfor (const [index, value] of arr.entries()) {\\n\\t\\t\\t\\tawait Promise.resolve(callback(value, index, arr));\\n\\t\\t\\t}\\n\\t\\t});\\n\\t}\\n}\\n
\\n
\\n

The only trick here is that callback may or may not return a promise. Unlike\\nPromise.all, the await operator requires a promise. We can use\\nPromise.resolve to wrap the result in a promise if it isn’t\\na promise already.

\\n

Putting it all together

\\n

One last improvement we can make to ergonomics is to add some static\\nmethods to remove redundant calls to PromiseCombinator.resolve.

\\n
\\n
class PromiseCombinator extends Promise {\\n\\tstatic map(value, callback) {\\n\\t\\treturn PromiseCombinator.resolve(value).map(callback);\\n\\t}\\n\\n\\tstatic filter(value, predicate) {\\n\\t\\treturn PromiseCombinator.resolve(value).filter(predicate);\\n\\t}\\n\\n\\tstatic forEach(value, callback) {\\n\\t\\treturn PromiseCombinator.resolve(value).forEach(callback);\\n\\t}\\n\\n\\tmap(callback) {\\n\\t\\treturn this.then(arr => {\\n\\t\\t\\tconst promises = arr.map(callback);\\n\\n\\t\\t\\treturn Promise.all(promises);\\n\\t\\t});\\n\\t}\\n\\n\\tfilter(predicate) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tconst values = await this.map(predicate);\\n\\n\\t\\t\\treturn arr.filter((_, i) => values[i]);\\n\\t\\t});\\n\\t}\\n\\n\\tforEach(callback) {\\n\\t\\treturn this.then(async arr => {\\n\\t\\t\\tfor (const [index, value] of arr.entries()) {\\n\\t\\t\\t\\tawait Promise.resolve(callback(value, index, arr));\\n\\t\\t\\t}\\n\\t\\t});\\n\\t}\\n}\\n\\nPromiseCombinator.filter([1, 2, 3, 4], x => x % 2)\\n\\t.map(x => x * 2)\\n\\t.then(values => assert.deepEqual(values, [2, 6]));\\n
\\n
\\n

Shameless plug

\\n

It was fun learning about promises and how they can be extended with more\\npowerful combinators. For a more complete collection of combinators, you may be\\ninterested in my library extends-promise.

\",\"frontmatter\":{\"title\":\"Extending Promise\",\"date\":\"February 16, 2018\"}}},\"pathContext\":{\"slug\":\"/blog/extending-promise/\",\"previous\":{\"fields\":{\"slug\":\"/blog/hello-world/\"},\"frontmatter\":{\"title\":\"Hello, World!\"}},\"next\":{\"fields\":{\"slug\":\"/blog/rust-overflow/\"},\"frontmatter\":{\"title\":\"Radians and Rust Integer Overflow\"}}}}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/json-loader!./.cache/json/blog-extending-promise.json\n// module id = 364\n// module chunks = 230700223712971"],"sourceRoot":""}