@antoniovdlc/defer
Advanced tools
Comparing version 0.0.1 to 0.1.0
@@ -1,1 +0,1 @@ | ||
"use strict";function e(e,r,t,n){return new(t||(t=Promise))((function(o,u){function c(e){try{i(n.next(e))}catch(e){u(e)}}function a(e){try{i(n.throw(e))}catch(e){u(e)}}function i(e){var r;e.done?o(e.value):(r=e.value,r instanceof t?r:new t((function(e){e(r)}))).then(c,a)}i((n=n.apply(e,r||[])).next())}))}function r(e,r){var t,n,o,u,c={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return u={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function a(u){return function(a){return function(u){if(t)throw new TypeError("Generator is already executing.");for(;c;)try{if(t=1,n&&(o=2&u[0]?n.return:u[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,u[1])).done)return o;switch(n=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return c.label++,{value:u[1],done:!1};case 5:c.label++,n=u[1],u=[0];continue;case 7:u=c.ops.pop(),c.trys.pop();continue;default:if(!(o=c.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){c=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){c.label=u[1];break}if(6===u[0]&&c.label<o[1]){c.label=o[1],o=u;break}if(o&&c.label<o[2]){c.label=o[2],c.ops.push(u);break}o[2]&&c.ops.pop(),c.trys.pop();continue}u=r.call(e,c)}catch(e){u=[6,e],n=0}finally{t=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,a])}}}Object.defineProperty(exports,"__esModule",{value:!0}),Array.isArray(Function.prototype.__$_deferArr)||(Function.prototype.__$_deferArr=[]),exports.defer=function(e,r){"Function"===r.constructor.name?setTimeout(e,0):"AsyncFunction"===r.constructor.name&&r.__$_deferArr.push(e)},exports.deferrable=function(t){var n=this;return function(){return e(n,void 0,void 0,(function(){var e,n;return r(this,(function(r){switch(r.label){case 0:return[4,t()];case 1:r.sent(),e=0,n=t.__$_deferArr.length,r.label=2;case 2:return e<n?[4,t.__$_deferArr[e]()]:[3,5];case 3:r.sent(),r.label=4;case 4:return e++,[3,2];case 5:return[2]}}))}))}}; | ||
"use strict";function e(e,r,n,t){return new(n||(n=Promise))((function(o,u){function a(e){try{i(t.next(e))}catch(e){u(e)}}function c(e){try{i(t.throw(e))}catch(e){u(e)}}function i(e){var r;e.done?o(e.value):(r=e.value,r instanceof n?r:new n((function(e){e(r)}))).then(a,c)}i((t=t.apply(e,r||[])).next())}))}function r(e,r){var n,t,o,u,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return u={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function c(u){return function(c){return function(u){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,t&&(o=2&u[0]?t.return:u[0]?t.throw||((o=t.return)&&o.call(t),0):t.next)&&!(o=o.call(t,u[1])).done)return o;switch(t=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return a.label++,{value:u[1],done:!1};case 5:a.label++,t=u[1],u=[0];continue;case 7:u=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){a=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){a.label=u[1];break}if(6===u[0]&&a.label<o[1]){a.label=o[1],o=u;break}if(o&&a.label<o[2]){a.label=o[2],a.ops.push(u);break}o[2]&&a.ops.pop(),a.trys.pop();continue}u=r.call(e,a)}catch(e){u=[6,e],t=0}finally{n=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,c])}}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.defer=function(e,r){"Function"===r.constructor.name?setTimeout(e,0):"AsyncFunction"===r.constructor.name&&(Array.isArray(r.__$_deferArr)||(r.__$_deferArr=[]),r.__$_deferArr.push(e))},exports.deferrable=function(n){var t=this;return function(){return e(t,void 0,void 0,(function(){var e,t;return r(this,(function(r){switch(r.label){case 0:return[4,n()];case 1:r.sent(),e=0,t=n.__$_deferArr.length,r.label=2;case 2:return e<t?[4,n.__$_deferArr[e]()]:[3,5];case 3:r.sent(),r.label=4;case 4:return e++,[3,2];case 5:return[2]}}))}))}}; |
@@ -1,1 +0,1 @@ | ||
function e(e,n,r,t){return new(r||(r=Promise))((function(o,u){function c(e){try{i(t.next(e))}catch(e){u(e)}}function a(e){try{i(t.throw(e))}catch(e){u(e)}}function i(e){var n;e.done?o(e.value):(n=e.value,n instanceof r?n:new r((function(e){e(n)}))).then(c,a)}i((t=t.apply(e,n||[])).next())}))}function n(e,n){var r,t,o,u,c={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return u={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function a(u){return function(a){return function(u){if(r)throw new TypeError("Generator is already executing.");for(;c;)try{if(r=1,t&&(o=2&u[0]?t.return:u[0]?t.throw||((o=t.return)&&o.call(t),0):t.next)&&!(o=o.call(t,u[1])).done)return o;switch(t=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return c.label++,{value:u[1],done:!1};case 5:c.label++,t=u[1],u=[0];continue;case 7:u=c.ops.pop(),c.trys.pop();continue;default:if(!(o=c.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){c=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){c.label=u[1];break}if(6===u[0]&&c.label<o[1]){c.label=o[1],o=u;break}if(o&&c.label<o[2]){c.label=o[2],c.ops.push(u);break}o[2]&&c.ops.pop(),c.trys.pop();continue}u=n.call(e,c)}catch(e){u=[6,e],t=0}finally{r=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,a])}}}function r(e,n){"Function"===n.constructor.name?setTimeout(e,0):"AsyncFunction"===n.constructor.name&&n.__$_deferArr.push(e)}function t(r){var t=this;return function(){return e(t,void 0,void 0,(function(){var e,t;return n(this,(function(n){switch(n.label){case 0:return[4,r()];case 1:n.sent(),e=0,t=r.__$_deferArr.length,n.label=2;case 2:return e<t?[4,r.__$_deferArr[e]()]:[3,5];case 3:n.sent(),n.label=4;case 4:return e++,[3,2];case 5:return[2]}}))}))}}Array.isArray(Function.prototype.__$_deferArr)||(Function.prototype.__$_deferArr=[]);export{r as defer,t as deferrable}; | ||
function e(e,n,r,t){return new(r||(r=Promise))((function(o,u){function a(e){try{i(t.next(e))}catch(e){u(e)}}function c(e){try{i(t.throw(e))}catch(e){u(e)}}function i(e){var n;e.done?o(e.value):(n=e.value,n instanceof r?n:new r((function(e){e(n)}))).then(a,c)}i((t=t.apply(e,n||[])).next())}))}function n(e,n){var r,t,o,u,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return u={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function c(u){return function(c){return function(u){if(r)throw new TypeError("Generator is already executing.");for(;a;)try{if(r=1,t&&(o=2&u[0]?t.return:u[0]?t.throw||((o=t.return)&&o.call(t),0):t.next)&&!(o=o.call(t,u[1])).done)return o;switch(t=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return a.label++,{value:u[1],done:!1};case 5:a.label++,t=u[1],u=[0];continue;case 7:u=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){a=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){a.label=u[1];break}if(6===u[0]&&a.label<o[1]){a.label=o[1],o=u;break}if(o&&a.label<o[2]){a.label=o[2],a.ops.push(u);break}o[2]&&a.ops.pop(),a.trys.pop();continue}u=n.call(e,a)}catch(e){u=[6,e],t=0}finally{r=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,c])}}}function r(e,n){"Function"===n.constructor.name?setTimeout(e,0):"AsyncFunction"===n.constructor.name&&(Array.isArray(n.__$_deferArr)||(n.__$_deferArr=[]),n.__$_deferArr.push(e))}function t(r){var t=this;return function(){return e(t,void 0,void 0,(function(){var e,t;return n(this,(function(n){switch(n.label){case 0:return[4,r()];case 1:n.sent(),e=0,t=r.__$_deferArr.length,n.label=2;case 2:return e<t?[4,r.__$_deferArr[e]()]:[3,5];case 3:n.sent(),n.label=4;case 4:return e++,[3,2];case 5:return[2]}}))}))}}export{r as defer,t as deferrable}; |
{ | ||
"name": "@antoniovdlc/defer", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"description": "Go-like defer functions in JavaScript.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.cjs.js", |
139
README.md
@@ -1,1 +0,138 @@ | ||
# defer | ||
# defer | ||
[![version](https://img.shields.io/npm/v/@antoniovdlc/defer.svg)](http://npm.im/@antoniovdlc/defer) | ||
[![issues](https://img.shields.io/github/issues-raw/antoniovdlc/defer.svg)](https://github.com/AntonioVdlC/defer/issues) | ||
[![downloads](https://img.shields.io/npm/dt/@antoniovdlc/defer.svg)](http://npm.im/@antoniovdlc/defer) | ||
[![license](https://img.shields.io/npm/l/@antoniovdlc/defer.svg)](http://opensource.org/licenses/MIT) | ||
Go-like defer functions in JavaScript. | ||
## Installation | ||
This package is distributed via npm: | ||
``` | ||
npm install @antoniovdlc/defer | ||
``` | ||
## Motivation | ||
Go provides the very interesting concept of `defer`ing functions until the end of a function's execution. | ||
```go | ||
package main | ||
import "fmt" | ||
func main() { | ||
defer fmt.Println("world") | ||
fmt.Println("hello") | ||
} | ||
// hello | ||
// world | ||
``` | ||
Such built-in construct might be very useful in JavaScript for example, where we sometimes need to do some clean-up, and thus could potentially co-locate it with the instanciation. | ||
## Usage | ||
You can use this library either as an ES module or a CommonJS package: | ||
```js | ||
import { defer, deferrable } from "@antoniovdlc/defer"; | ||
``` | ||
*- or -* | ||
```js | ||
const { defer, deferrable } = require("@antoniovdlc/defer"); | ||
``` | ||
### defer(fn: Function, caller: Function) : void | ||
`defer` takes a function as argument, which will be called at the end of the execution of the caller function, and a caller function. | ||
For sync functions, `defer` simply puts the `fn` at the bottom of the call stack using `setTimeout(fn, 0)`. | ||
For async functions, it is a bit more tricky, and we keep track of deferred functions within the `caller` itself, via the property `__$_deferArr`. | ||
> Using `defer` in async functions requires them to be wrapper with `deferrable` to work properly. | ||
### deferrable(fn: Function) : Function | ||
`defer` works out of the box within sync functions. Unfortunately, for async functions, we need to use a wrapper: `deferrable`. | ||
This wrapper returns a function that will compute similarly to its argument, but helps keep track of all the deferred functions within it. | ||
## Examples | ||
Let's start with a simple translation of the Go code we shared previously: | ||
```js | ||
function main() { | ||
defer(() => console.log("world"); | ||
console.log("hello"); | ||
} | ||
main(); // hello world | ||
``` | ||
There can be as many `defer` calls in a function as you'd like: | ||
```js | ||
function f() { | ||
defer(() => console.log("1), f); | ||
console.log("2"); | ||
defer(() => console.log("3"), f); | ||
console.log("4") | ||
} | ||
f(); // 2 4 1 3 | ||
``` | ||
For async functions, we need to use `deferrable`: | ||
```js | ||
const f = deferrable(async function fn() { | ||
defer(async() => await new Promise( | ||
resolve => resolve(console.log("1")) | ||
), fn); | ||
await new Promise(resolve => setTimeout(() => resolve(console.log("2")))); | ||
defer(() => console.log("3"), fn); | ||
console.log("4") | ||
}); | ||
await f(); // 2 4 1 3 | ||
``` | ||
> `defer`red functions can also be async functions! | ||
## Previous Art | ||
Besides getting inspiration from Go's error handling, this package also draws inspiration from the following packages: | ||
- [golike-defer](https://www.npmjs.com/package/golike-defer) | ||
- [with-defer](https://www.npmjs.com/package/with-defer) | ||
- [@borderless-defer](https://www.npmjs.com/package/@borderless/defer) | ||
- ... and many more! | ||
## FAQ | ||
### Why not use any of the existing packages? | ||
Good you ask! | ||
There is probably a bit of selfishness in the belief that maybe I can implement this in a better way, but the main reason is to see if I can implement such a library and maybe add some goodies on top. | ||
This code, even though thoroughly tested with 100% code coverage, has not ran in production yet. As such, either you feel adventurous, or I would invite you to look for more mature libraries providing essentially the same functionalities (I've linked to a few I found myself right above, but there are many more). | ||
Anyway, thanks for stopping by! :) | ||
### Why do I need to pass in a `caller` function to `defer`? | ||
JavaScript engines used to support a `Function.caller` property that would have made it trivial to access the function in which `defer` was being called. Unfortunately, that property (amongst a couple of others) was dropped, hence the only feasible way (at least that I can think of) of getting access to the caller was by adding an extra parameter to `defer` directly. | ||
This means that `defer` only work in non-anonymous functions. | ||
### Why aren't the `defer`red functions called in last-in-first-out order like in Go? | ||
Good question! | ||
I'd say it comes down to personal preference, as I think it is easier to reason about the order of the `defer`red functions when they execute in the same order they appear in the code. | ||
## License | ||
MIT |
11650
138