├── .editorconfig ├── .gitignore ├── .jshintrc ├── .markdown-doctest-setup.js ├── .travis.yml ├── LICENSE ├── README.md ├── binarydisposable.js ├── code-of-conduct.md ├── compositedisposable.js ├── disposable.js ├── doc ├── binarydisposable.md ├── compositedisposable.md ├── disposable.md ├── narydisposable.md ├── refcountdisposable.md ├── serialdisposable.md └── singleassignmentdisposable.md ├── index.js ├── narydisposable.js ├── package.json ├── refcountdisposable.js ├── serialdisposable.js ├── singleassignmentdisposable.js └── test ├── binarydisposable.js ├── disposable.js ├── narydisposable.js ├── refcountdisposable.js ├── serialdisposable.js └── singleassignmentdisposable.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = false 6 | indent_style = space 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true, 14 | "-W030": true, 15 | "predef": [ "Promise" ] 16 | } 17 | -------------------------------------------------------------------------------- /.markdown-doctest-setup.js: -------------------------------------------------------------------------------- 1 | var disposables = require(__dirname); 2 | 3 | module.exports = { 4 | require: { 5 | 'rx.disposables': disposables 6 | }, 7 | 8 | globals: disposables 9 | } 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | - 4 6 | - 5 7 | env: 8 | global: 9 | - secure: "JwyiLIEV6S7wzr9eUgQ/rP8BeeSY6ZabknHpUKSk4miA7d+/acFeuMAYu0d79BG8ndFIdG9EYbA7ZY1TH/metqDTrExzYLooa0XrAYg2x+cDSboII9albVn5bvdmmWIcgcmcZwKvi5JYLHWcA3Px84Aaf3YXN9V4lS1uLhl0eBI=" 10 | - secure: "BVYlZy3vIt21bhrzKPgQzRlbwGCBrdBtRPRvX/qCGi1jYAoAtrT0bYllZpNqduPLouW3LaJDwOJx9zLDmZDwKDvPgTinpVwmkhZYRFl1kNweku3ZfeHR5ejOVYvdQEqVU4rOtTBLk6emItEPTuFtC9SPSYQZQtjnZAjHTg0jqLU=" 11 | notifications: 12 | slack: reactivex:e424dAgQ2W9kuRMe6ngxHQbv 13 | webhooks: 14 | urls: 15 | - https://webhooks.gitter.im/e/8f1482d7420d95b647ce 16 | on_success: change # options: [always|never|change] default: always 17 | on_failure: always # options: [always|never|change] default: always 18 | on_start: false # default: false 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/Reactive-Extensions/rx.disposables.svg)](https://travis-ci.org/Reactive-Extensions/rx.disposables) 2 | [![GitHub version](https://img.shields.io/github/tag/reactive-extensions/rx.disposables.svg)](https://github.com/Reactive-Extensions/rx.disposables) 3 | [![NPM version](https://img.shields.io/npm/v/rx.disposables.svg)](https://www.npmjs.com/package/rx.disposables) 4 | [![Downloads](https://img.shields.io/npm/dm/rx.disposables.svg)](https://www.npmjs.com/package/rx.disposables) 5 | # `rx.disposables` - RxJS disposables 6 | 7 | This is a standalone version of the RxJS disposable classes which can manage the lifetime of any given resource. 8 | 9 | This includes the following disposables with their documentation: 10 | - [`BinaryDisposable`](doc/binarydisposable.md) 11 | - [`CompositeDisposable`](doc/compositedisposable.md) 12 | - [`Disposable`](doc/disposable.md) 13 | - [`NAryDisposable`](doc/narydisposable.md) 14 | - [`SerialDisposable`](doc/serialdisposable.md) 15 | - [`SingleAssignmentDisposable`](doc/singleassignmentdisposable.md) 16 | 17 | ## Installation 18 | 19 | The `rx.disposables` library can be installed by the following: 20 | 21 | ### NPM 22 | ```bash 23 | $ npm install rx.disposables 24 | ``` 25 | 26 | ## Usage 27 | 28 | Here is some basic usage a simple `Disposable` to handle resources: 29 | ```js 30 | const Disposable = require('rx.disposables').Disposable; 31 | 32 | // Imagine this to be some sort of resource 33 | let isDisposed = false; 34 | const d = Disposable.create(() => isDisposed = true); 35 | 36 | d.dispose(); 37 | console.log(`isDisposed is ${isDisposed}`); 38 | // => isDisposed is true 39 | ``` 40 | 41 | There may be some instances when you want the disposable to be ref counted so that it only disposes when all dependent observables have been disposed, for example a file handle. 42 | 43 | ```js 44 | const d = require('rx.disposables'); 45 | 46 | // Imagine this to be a resource 47 | let isDisposed = false; 48 | const dd = d.Disposable.create(() => isDisposed = true); 49 | 50 | const r = new d.RefCountDisposable(dd); 51 | 52 | // Make two references 53 | const d1 = r.getDisposable(); 54 | const d2 = r.getDisposable(); 55 | 56 | // Clean up each 57 | d1.dispose(); 58 | d2.dispose(); 59 | 60 | // Now we can clean up now that ref count went to zero 61 | r.dispose(); 62 | console.log(`isDisposed is ${isDisposed}`); 63 | // => isDisposed is true 64 | ``` 65 | 66 | We can also handle collections in multiple ways, either with the immutable disposables such as the `BinaryDisposable` for handling two disposables, and `NAryDisposable` for handling arrays. If you wish to add and remove disposables from a list, you can use the `CompositeDisposable`. 67 | 68 | ```js 69 | const d = require('rx.disposables'); 70 | 71 | const d1 = d.Disposable.create(() => console.log('one')); 72 | const d2 = d.Disposable.create(() => console.log('two')); 73 | 74 | const c = new d.CompositeDisposable(d1, d2); 75 | 76 | const d3 = d.Disposable.create(() => console.log('three')); 77 | c.add(d3); 78 | 79 | c.remove(d3); 80 | // => three 81 | 82 | c.dispose(); 83 | // => one 84 | // => two 85 | ``` 86 | 87 | There may also be times when you need to set the disposable later, so you can manage it in a container such as the `SingleAssignmentDisposable` for handling only one assignment, and the `SerialDisposable` which disposes the previous and sets the new disposable if the `SerialDisposable` has not been disposed. 88 | 89 | For example, we could set it later using the `SingleAssignmentDisposable`: 90 | 91 | ```js 92 | const d = require('rx.disposables'); 93 | 94 | const sad = new d.SingleAssignmentDisposable(); 95 | 96 | const d1 = d.Disposable.create(() => console.log('one')); 97 | 98 | // Set the disposable later 99 | sad.setDisposable(d1); 100 | 101 | sad.dispose(); 102 | // => one 103 | ``` 104 | 105 | And we could also use the `SerialDisposable` if we have the need to swap out our disposable: 106 | 107 | ```js 108 | const d = require('rx.disposables'); 109 | 110 | const sd = new d.SerialDisposable(); 111 | 112 | const d1 = d.Disposable.create(() => console.log('one')); 113 | 114 | // Set the disposable later 115 | sd.setDisposable(d1); 116 | 117 | const d2 = d.Disposable.create(() => console.log('two')); 118 | 119 | // Replace the disposable 120 | sd.setDisposable(d2); 121 | // => one 122 | 123 | sd.dispose(); 124 | // => two 125 | ``` 126 | 127 | ## Contributing 128 | 129 | We appreciate any contributions by the community as long as they abide by the [Code of Conduct](code-of-conduct.md). 130 | 131 | Want to get started? Here are some ways you can get involved. 132 | 1. Documentation 133 | - Examples 134 | - How Do I? 135 | - API Documentation 136 | 2. Code 137 | - Additional disposables 138 | - Unit tests 139 | 140 | # LICENSE 141 | 142 | The MIT License (MIT) 143 | 144 | Copyright (c) 2016 Microsoft Corporation 145 | 146 | Permission is hereby granted, free of charge, to any person obtaining a copy 147 | of this software and associated documentation files (the "Software"), to deal 148 | in the Software without restriction, including without limitation the rights 149 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 150 | copies of the Software, and to permit persons to whom the Software is 151 | furnished to do so, subject to the following conditions: 152 | 153 | The above copyright notice and this permission notice shall be included in all 154 | copies or substantial portions of the Software. 155 | 156 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 158 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 159 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 160 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 161 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 162 | SOFTWARE. 163 | -------------------------------------------------------------------------------- /binarydisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Represents a group of disposable resources that are disposed together. 5 | * @constructor 6 | * Creates a new group of disposable resources that are disposed together. 7 | * @param [Any] first The first disposable resoruce to add to the group. 8 | * @param [Any] second The second disposable resoruce to add to the group. 9 | */ 10 | function BinaryDisposable(first, second) { 11 | this._first = first; 12 | this._second = second; 13 | this.isDisposed = false; 14 | } 15 | 16 | /** 17 | * Disposes all disposables in the group. 18 | */ 19 | BinaryDisposable.prototype.dispose = function () { 20 | if (!this.isDisposed) { 21 | this.isDisposed = true; 22 | var old1 = this._first; 23 | this._first = null; 24 | old1 && old1.dispose(); 25 | var old2 = this._second; 26 | this._second = null; 27 | old2 && old2.dispose(); 28 | } 29 | }; 30 | 31 | module.exports = BinaryDisposable; 32 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct # 2 | 3 | [_Adapted from the Rust Code of Conduct_](https://github.com/rust-lang/rust/wiki/Note-development-policy#conduct) 4 | 5 | We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristic. 6 | - On any communication medium, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. 7 | - Please be kind and courteous. There's no need to be mean or rude. 8 | - Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. 9 | - Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. 10 | - We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. 11 | - Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one the RxJS team immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. 12 | - Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. 13 | -------------------------------------------------------------------------------- /compositedisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Represents a group of disposable resources that are disposed together. 5 | * @constructor 6 | */ 7 | function CompositeDisposable () { 8 | var args = [], i, len; 9 | if (Array.isArray(arguments[0])) { 10 | args = arguments[0]; 11 | len = args.length; 12 | } else { 13 | len = arguments.length; 14 | args = new Array(len); 15 | for(i = 0; i < len; i++) { args[i] = arguments[i]; } 16 | } 17 | this._disposables = args; 18 | this.isDisposed = false; 19 | this.length = args.length; 20 | } 21 | 22 | /** 23 | * Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed. 24 | * @param {Any} item Disposable to add. 25 | */ 26 | CompositeDisposable.prototype.add = function (item) { 27 | if (this.isDisposed) { 28 | item.dispose(); 29 | } else { 30 | this._disposables.push(item); 31 | this.length++; 32 | } 33 | }; 34 | 35 | /** 36 | * Removes and disposes the first occurrence of a disposable from the CompositeDisposable. 37 | * @param {Any} item Disposable to remove. 38 | * @returns {Boolean} true if found; false otherwise. 39 | */ 40 | CompositeDisposable.prototype.remove = function (item) { 41 | var shouldDispose = false; 42 | if (!this.isDisposed) { 43 | var idx = this._disposables.indexOf(item); 44 | if (idx !== -1) { 45 | shouldDispose = true; 46 | this._disposables.splice(idx, 1); 47 | this.length--; 48 | item.dispose(); 49 | } 50 | } 51 | return shouldDispose; 52 | }; 53 | 54 | /** 55 | * Disposes all disposables in the group and removes them from the group but 56 | * does not dispose the CompositeDisposable. 57 | */ 58 | CompositeDisposable.prototype.clear = function () { 59 | if (!this.isDisposed) { 60 | var len = this._disposables.length, currentDisposables = new Array(len); 61 | for(var i = 0; i < len; i++) { currentDisposables[i] = this._disposables[i]; } 62 | this._disposables = []; 63 | this.length = 0; 64 | 65 | for (i = 0; i < len; i++) { 66 | currentDisposables[i].dispose(); 67 | } 68 | } 69 | }; 70 | 71 | /** 72 | * Disposes all disposables in the group and removes them from the group. 73 | */ 74 | CompositeDisposable.prototype.dispose = function () { 75 | if (!this.isDisposed) { 76 | this.isDisposed = true; 77 | var len = this._disposables.length, currentDisposables = new Array(len); 78 | for(var i = 0; i < len; i++) { currentDisposables[i] = this._disposables[i]; } 79 | this._disposables = []; 80 | this.length = 0; 81 | 82 | for (i = 0; i < len; i++) { 83 | currentDisposables[i].dispose(); 84 | } 85 | } 86 | }; 87 | 88 | module.exports = CompositeDisposable; 89 | -------------------------------------------------------------------------------- /disposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function noop () { } 4 | 5 | var isFunction = module.exports = (function () { 6 | var isFn = function (value) { 7 | return typeof value === 'function' || false; 8 | }; 9 | 10 | // fallback for older versions of Chrome and Safari 11 | if (isFn(/x/)) { 12 | isFn = function(value) { 13 | return typeof value === 'function' && 14 | Object.prototype.toString.call(value) === '[object Function]'; 15 | }; 16 | } 17 | return isFn; 18 | }()); 19 | 20 | /** 21 | * Provides a set of static methods for creating Disposables. 22 | * @param {Function} action Action to run during the first call to dispose. 23 | * The action is guaranteed to be run at most once. 24 | */ 25 | function Disposable (action) { 26 | this.isDisposed = false; 27 | this.action = isFunction(action) ? action : noop; 28 | } 29 | 30 | /** Performs the task of cleaning up resources. */ 31 | Disposable.prototype.dispose = function () { 32 | if (!this.isDisposed) { 33 | this.action(); 34 | this.isDisposed = true; 35 | } 36 | }; 37 | 38 | /** 39 | * Creates a disposable object that invokes the specified action when disposed. 40 | * @param {Function} dispose Action to run during the first call to dispose. 41 | * The action is guaranteed to be run at most once. 42 | * @return {Disposable} The disposable object that runs the given action upon disposal. 43 | */ 44 | Disposable.create = function (action) { return new Disposable(action); }; 45 | 46 | /** 47 | * Gets the disposable that does nothing when disposed. 48 | */ 49 | Disposable.empty = { dispose: noop }; 50 | 51 | /** 52 | * Validates whether the given object is a disposable 53 | * @param {Object} Object to test whether it has a dispose method 54 | * @returns {Boolean} true if a disposable object, else false. 55 | */ 56 | Disposable.isDisposable = function (d) { 57 | return d && isFunction(d.dispose); 58 | }; 59 | 60 | Disposable._fixup = function (result) { 61 | return Disposable.isDisposable(result) ? result : Disposable.empty; 62 | }; 63 | 64 | module.exports = Disposable; 65 | -------------------------------------------------------------------------------- /doc/binarydisposable.md: -------------------------------------------------------------------------------- 1 | # `BinaryDisposable` class # 2 | 3 | Represents an immutable group of two disposable resources that are disposed together. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of a `BinaryDisposable`. 8 | 9 | ```js 10 | const d1 = Disposable.create(() => console.log('one')); 11 | const d2 = Disposable.create(() => console.log('two')); 12 | 13 | // Initialize with two disposables 14 | const disposables = new BinaryDisposable(d1, d2); 15 | 16 | disposables.dispose(); 17 | // => one 18 | // => two 19 | ``` 20 | 21 | ## `BinaryDisposable Constructor` ## 22 | - [`constructor`](#binarydisposablefirst-second) 23 | 24 | ## `BinaryDisposable Instance Methods` ## 25 | - [`dispose`](#binarydisposableprototypedispose) 26 | 27 | ## `BinaryDisposable Instance Properties` ## 28 | - [`isDisposed`](#isdisposed) 29 | 30 | ## _BinaryDisposable Constructor_ ## 31 | 32 | ### `BinaryDisposable(first, second)` 33 | 34 | Creates a new group of two disposable resources that are disposed together. 35 | 36 | #### Arguments 37 | 1. `first`: `Disposable` - The first disposable resource to add to the group. 38 | 2. `second`: `Disposable` - The second disposable resource to add to the group. 39 | 40 | #### Example 41 | ```js 42 | const d1 = Disposable.create(() => console.log('one')); 43 | const d2 = Disposable.create(() => console.log('two')); 44 | 45 | // Initialize with two disposables 46 | const disposables = new BinaryDisposable(d1, d2); 47 | 48 | disposables.dispose(); 49 | // => one 50 | // => two 51 | ``` 52 | 53 | * * * 54 | 55 | ## _BinaryDisposable Instance Methods_ ## 56 | 57 | ### `BinaryDisposable.prototype.dispose()` 58 | 59 | Disposes the underlying disposables. 60 | 61 | #### Example 62 | 63 | ```js 64 | const d1 = Disposable.create(() => console.log('one')); 65 | const d2 = Disposable.create(() => console.log('two')); 66 | 67 | const disposables = new BinaryDisposable(d1, d2); 68 | 69 | disposables.dispose(); 70 | // => one 71 | // => two 72 | 73 | console.log(disposables.length); 74 | // => 0 75 | ``` 76 | * * * 77 | 78 | ## _BinaryDisposable Instance Properties_ ## 79 | 80 | ### `isDisposed` 81 | 82 | Gets a value that indicates whether the object is disposed. 83 | 84 | #### Example 85 | ```js 86 | const d1 = Disposable.create(() => console.log('one')); 87 | const d2 = Disposable.create(() => console.log('two')); 88 | 89 | const disposables = new BinaryDisposable(d1, d2); 90 | 91 | console.log(disposables.isDisposed); 92 | // => false 93 | 94 | disposables.dispose(); 95 | // => disposed 96 | 97 | console.log(disposables.isDisposed); 98 | // => true 99 | ``` 100 | 101 | * * * 102 | -------------------------------------------------------------------------------- /doc/compositedisposable.md: -------------------------------------------------------------------------------- 1 | # `CompositeDisposable` class # 2 | 3 | Represents a group of disposable resources that are disposed together that can be added to and removed from. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of a `CompositeDisposable`. 8 | 9 | ```js 10 | const d1 = Disposable.create(() => console.log('one')); 11 | const d2 = Disposable.create(() => console.log('two')); 12 | 13 | // Initialize with two disposables 14 | const disposables = new CompositeDisposable(d1, d2); 15 | 16 | disposables.dispose(); 17 | // => one 18 | // => two 19 | ``` 20 | 21 | ## `CompositeDisposable` Constructor ## 22 | - [`constructor`](#compositedisposablergs) 23 | 24 | ## `CompositeDisposable` Instance Methods ## 25 | - [`add`](#compositedisposableprototypeadditem) 26 | - [`clear`](#compositedisposableprototypeclear) 27 | - [`dispose`](#compositedisposableprototypedispose) 28 | - [`remove`](#compositedisposableprototyperemoveitem) 29 | 30 | ## `CompositeDisposable` Instance Properties ## 31 | - [`isDisposed`](#isdisposed) 32 | - [`length`](#length) 33 | 34 | ## _CompositeDisposable Constructor_ ## 35 | 36 | ### `CompositeDisposable(...args)` 37 | 38 | Initializes a new instance of the `CompositeDisposable` class from a group of disposables. 39 | 40 | #### Arguments 41 | 1. `args`: `Array|arguments` - Disposables that will be disposed together. 42 | 43 | #### Example 44 | ```js 45 | const d1 = Disposable.create(() => console.log('one')); 46 | const d2 = Disposable.create(() => console.log('two')); 47 | 48 | // Initialize with two disposables 49 | const disposables = new CompositeDisposable(d1, d2); 50 | 51 | disposables.dispose(); 52 | // => one 53 | // => two 54 | ``` 55 | 56 | * * * 57 | 58 | ## _CompositeDisposable Instance Methods_ ## 59 | 60 | ### `CompositeDisposable.prototype.add(item)` 61 | 62 | Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed. 63 | 64 | #### Arguments 65 | 1. `item` `Disposable`: Disposable to add. 66 | 67 | #### Example 68 | 69 | ```js 70 | const disposables = new CompositeDisposable(); 71 | 72 | const d1 = Disposable.create(() => console.log('one')); 73 | 74 | disposables.add(d1); 75 | 76 | disposables.dispose(); 77 | // => one 78 | ``` 79 | 80 | * * * 81 | 82 | ### `CompositeDisposable.prototype.clear()` 83 | 84 | Disposes all disposables in the group and removes them from the group but does not dispose the CompositeDisposable. 85 | 86 | #### Example 87 | 88 | ```js 89 | const d1 = Disposable.create(() => console.log('one')); 90 | const d2 = Disposable.create(() => console.log('two')); 91 | 92 | const disposables = new CompositeDisposable(d1, d2); 93 | 94 | disposables.dispose(); 95 | // => one 96 | // => two 97 | 98 | console.log(disposables.isDisposed); 99 | // => false 100 | ``` 101 | 102 | * * * 103 | 104 | ### `CompositeDisposable.prototype.dispose()` 105 | 106 | Disposes all disposables in the group and removes them from the group. 107 | 108 | #### Example 109 | 110 | ```js 111 | const d1 = Disposable.create(() => console.log('one')); 112 | const d2 = Disposable.create(() => console.log('two')); 113 | 114 | const disposables = new CompositeDisposable(d1, d2); 115 | 116 | disposables.dispose(); 117 | // => one 118 | // => two 119 | 120 | console.log(disposables.length); 121 | // => 0 122 | ``` 123 | 124 | * * * 125 | 126 | ### `CompositeDisposable.prototype.remove(item)` 127 | 128 | Removes and disposes the first occurrence of a disposable from the CompositeDisposable. 129 | 130 | #### Arguments 131 | 1. `item` `Disposable`: Disposable to remove. 132 | 133 | #### Returns 134 | `Boolean`: `true` if the disposable was found and disposed; otherwise, `false`. 135 | 136 | #### Example 137 | 138 | ```js 139 | const disposables = new CompositeDisposable(); 140 | 141 | const d1 = Disposable.create(function () { 142 | console.log('one'); 143 | }); 144 | 145 | disposables.add(d1); 146 | 147 | console.log(disposables.remove(d1)); 148 | // => true 149 | ``` 150 | 151 | * * * 152 | 153 | ## _CompositeDisposable Instance Properties_ ## 154 | 155 | ### `isDisposed` 156 | # 157 | 158 | Gets a value that indicates whether the object is disposed. 159 | 160 | #### Example 161 | ```js 162 | const disposables = new CompositeDisposable(); 163 | 164 | const d1 = Disposable.create(() => console.log('disposed')); 165 | 166 | disposables.add(d1); 167 | 168 | console.log(disposables.isDisposed); 169 | // => false 170 | 171 | disposables.dispose(); 172 | // => disposed 173 | 174 | console.log(disposables.isDisposed); 175 | // => true 176 | ``` 177 | 178 | * * * 179 | 180 | ### `length` 181 | # 182 | 183 | Gets the number of disposables in the CompositeDisposable. 184 | 185 | #### Example 186 | ```js 187 | const disposables = new CompositeDisposable(); 188 | 189 | const d1 = Disposable.create(() => console.log('disposed')); 190 | 191 | disposables.add(d1); 192 | 193 | console.log(disposables.length); 194 | // => 1 195 | 196 | disposables.dispose(); 197 | // => disposed 198 | 199 | console.log(disposables.length); 200 | // => 0 201 | ``` 202 | 203 | * * * 204 | -------------------------------------------------------------------------------- /doc/disposable.md: -------------------------------------------------------------------------------- 1 | # `Disposable` class # 2 | 3 | Provides a set of static methods for creating Disposables, which defines a method to release allocated resources. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of an `Disposable`. 8 | 9 | ```js 10 | const disposable = Disposable.create(() => console.log('disposed')); 11 | 12 | disposable.dispose(); 13 | // => disposed 14 | ``` 15 | 16 | ## `Disposable` Class Methods ## 17 | - [`create`](#disposablecreateaction) 18 | - [`isDisposable`](#disposableisdisposabled) 19 | 20 | ## `Disposable` Class Properties ## 21 | - [`empty`](#disposableempty) 22 | 23 | ## `Disposable` Instance Methods ## 24 | - [`dispose`](#disposableprototypedispose) 25 | 26 | ## _Class Methods_ ## 27 | 28 | ### `Disposable.create(action)` 29 | 30 | Creates a disposable object that invokes the specified action when disposed. 31 | 32 | #### Arguments 33 | 1. `action` `Function`: Function to run during the first call to `dispose`. The action is guaranteed to be run at most once. 34 | 35 | #### Returns 36 | `Disposable`: The disposable object that runs the given action upon disposal. 37 | 38 | #### Example 39 | ```js 40 | const disposable = Disposable.create(() => console.log('disposed')); 41 | 42 | disposable.dispose(); 43 | // => disposed 44 | ``` 45 | 46 | * * * 47 | 48 | ### `Disposable.isDisposable(d)` 49 | 50 | Creates a disposable object that invokes the specified action when disposed. 51 | 52 | #### Arguments 53 | 1. `d`: `Object` - Object to validate whether it has a dispose method. 54 | 55 | #### Returns 56 | `Boolean` - `true` if is a disposable object, else `false`. 57 | 58 | #### Example 59 | ```js 60 | const disposable = Disposable.empty; 61 | console.log(Disposable.isDisposable(disposable)); 62 | // => true 63 | ``` 64 | 65 | * * * 66 | 67 | ## _Disposable Class Properties_ ## 68 | 69 | ### `Disposable.empty` 70 | 71 | Gets the disposable that does nothing when disposed. 72 | 73 | #### Returns 74 | `Disposable`: The disposable that does nothing when disposed. 75 | 76 | #### Example 77 | 78 | ```js 79 | const disposable = Disposable.empty; 80 | 81 | disposable.dispose(); // Does nothing 82 | ``` 83 | 84 | * * * 85 | 86 | ## _Disposable Instance Methods_ ## 87 | 88 | ### `Disposable.prototype.dispose()` 89 | 90 | Performs the task of cleaning up resources. 91 | 92 | #### Example 93 | 94 | ```js 95 | const disposable = Disposable.create(() => console.log('disposed')); 96 | 97 | disposable.dispose(); 98 | // => disposed 99 | ``` 100 | * * * 101 | -------------------------------------------------------------------------------- /doc/narydisposable.md: -------------------------------------------------------------------------------- 1 | # `NAryDisposable` class # 2 | 3 | Represents an immutable group of disposable resources that are disposed together. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of a `NAryDisposable`. 8 | 9 | ```js 10 | const d1 = Disposable.create(() => console.log('one')); 11 | const d2 = Disposable.create(() => console.log('two')); 12 | const d3 = Disposable.create(() => console.log('three')); 13 | 14 | // Initialize with two disposables 15 | const disposables = new NAryDisposable([d1, d2, d3]); 16 | 17 | disposables.dispose(); 18 | // => one 19 | // => two 20 | // => three 21 | ``` 22 | 23 | ## `NAryDisposable Constructor` ## 24 | - [`constructor`](#narydisposabledisposables) 25 | 26 | ## `NAryDisposable Instance Methods` ## 27 | - [`dispose`](#narydisposableprototypedispose) 28 | 29 | ## `NAryDisposable Instance Properties` ## 30 | - [`isDisposed`](#isdisposed) 31 | 32 | ## _NAryDisposable Constructor_ ## 33 | 34 | ### `NAryDisposable(disposables)` 35 | 36 | Creates a new group of disposable resources that are disposed together. 37 | 38 | #### Arguments 39 | 1. `disposables`: `Array` - Disposables that will be disposed together. 40 | 41 | #### Example 42 | ```js 43 | const d1 = Disposable.create(() => console.log('one')); 44 | const d2 = Disposable.create(() => console.log('two')); 45 | const d3 = Disposable.create(() => console.log('three')); 46 | 47 | // Initialize with two disposables 48 | const disposables = new NAryDisposable([d1, d2, d3]); 49 | 50 | disposables.dispose(); 51 | // => one 52 | // => two 53 | // => three 54 | ``` 55 | 56 | * * * 57 | 58 | ## _NAryDisposable Instance Methods_ ## 59 | 60 | ### `NAryDisposable.prototype.dispose()` 61 | 62 | Disposes the underlying disposables. 63 | 64 | #### Example 65 | 66 | ```js 67 | const d1 = Disposable.create(() => console.log('one')); 68 | const d2 = Disposable.create(() => console.log('two')); 69 | const d3 = Disposable.create(() => console.log('three')); 70 | 71 | // Initialize with two disposables 72 | const disposables = new NAryDisposable([d1, d2, d3]); 73 | 74 | disposables.dispose(); 75 | // => one 76 | // => two 77 | // => three 78 | ``` 79 | * * * 80 | 81 | ## _NAryDisposable Instance Properties_ ## 82 | 83 | ### `isDisposed` 84 | 85 | Gets a value that indicates whether the object is disposed. 86 | 87 | #### Example 88 | ```js 89 | const d1 = Disposable.create(() => console.log('one')); 90 | const d2 = Disposable.create(() => console.log('two')); 91 | const d3 = Disposable.create(() => console.log('three')); 92 | 93 | const disposables = new NAryDisposable([d1, d2, d3]); 94 | 95 | console.log(disposables.isDisposed); 96 | // => false 97 | 98 | disposables.dispose(); 99 | // => disposed 100 | 101 | console.log(disposables.isDisposed); 102 | // => true 103 | ``` 104 | 105 | * * * 106 | -------------------------------------------------------------------------------- /doc/refcountdisposable.md: -------------------------------------------------------------------------------- 1 | # `RefCountDisposable` class # 2 | 3 | Represents a disposable resource that only disposes its underlying disposable resource when all dependent disposable objects have been disposed. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of a `RefCountDisposable`. 8 | 9 | ```js 10 | const d = Disposable.create(() => console.log('disposed')); 11 | 12 | const r = new RefCountDisposable(d); 13 | 14 | const d1 = r.getDisposable(); 15 | const d2 = r.getDisposable(); 16 | 17 | d1.dispose(); 18 | console.log(d.isDisposed); 19 | // => false 20 | 21 | d2.dispose(); 22 | console.log(d.isDisposed); 23 | // => false 24 | 25 | r.dispose(); 26 | // => disposed 27 | console.log(d.isDisposed); 28 | // => true 29 | ``` 30 | 31 | ## `RefCountDisposable` Constructor ## 32 | - [`constructor`](#refcountdisposabledisposable) 33 | 34 | ## `RefCountDisposable` Instance Methods ## 35 | - [`dispose`](#refcountdisposableprototypedispose) 36 | - [`getDisposable`](#refcountdisposableprototypegetdisposable) 37 | - [`setDisposable`](#refcountdisposableprototypesetdisposable) 38 | 39 | ## `RefCountDisposable` Instance Properties ## 40 | - [`isDisposed`](#isdisposed) 41 | 42 | ## _RefCountDisposable Constructor_ ## 43 | 44 | ### `RefCountDisposable(disposable)` 45 | 46 | Initializes a new instance of the `RefCountDisposable` class with the specified disposable. 47 | 48 | #### Example 49 | ```js 50 | const d = Disposable.create(() => console.log('disposed')); 51 | 52 | const r = new RefCountDisposable(d); 53 | 54 | r.dispose(); 55 | // => disposed 56 | ``` 57 | 58 | * * * 59 | 60 | ## _RefCountDisposable Instance Methods_ ## 61 | 62 | ### `RefCountDisposable.prototype.dispose()` 63 | 64 | Disposes the underlying disposable only when all dependent disposables have been disposed. 65 | 66 | #### Example 67 | 68 | ```js 69 | const d = Disposable.create(() => console.log('disposed')); 70 | 71 | const r = new RefCountDisposable(d); 72 | 73 | const d1 = r.getDisposable(); 74 | const d2 = r.getDisposable(); 75 | 76 | d1.dispose(); 77 | console.log(d.isDisposed); 78 | // => false 79 | 80 | d2.dispose(); 81 | console.log(d.isDisposed); 82 | // => false 83 | 84 | // All have been disposed 85 | r.dispose(); 86 | // => disposed 87 | console.log(d.isDisposed); 88 | // => true 89 | ``` 90 | 91 | * * * 92 | 93 | ### `RefCountDisposable.prototype.getDisposable()` 94 | 95 | Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable. 96 | 97 | #### Returns 98 | `Disposable` - A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime. 99 | 100 | #### Example 101 | 102 | ```js 103 | const d = Disposable.create(() => console.log('disposed')); 104 | 105 | const r = new RefCountDisposable(d); 106 | 107 | // Ref count by two 108 | const d1 = r.getDisposable(); 109 | const d2 = r.getDisposable(); 110 | 111 | // Dispose both 112 | d1.dispose(); 113 | d2.dispose(); 114 | 115 | r.dispose(); 116 | // => disposed 117 | console.log(d.isDisposed); 118 | // => true 119 | ``` 120 | 121 | * * * 122 | 123 | ## _RefCountDisposable Instance Properties_ ## 124 | 125 | ### `isDisposed` 126 | 127 | Gets a value that indicates whether the object is disposed. 128 | 129 | #### Example 130 | ```js 131 | const d = Disposable.create(() => console.log('disposed')); 132 | 133 | var r = new RefCountDisposable(d); 134 | 135 | console.log(d.isDisposed); 136 | // => false 137 | 138 | r.dispose(); 139 | // => disposed 140 | 141 | console.log(r.isDisposed); 142 | // => true 143 | ``` 144 | 145 | * * * 146 | -------------------------------------------------------------------------------- /doc/serialdisposable.md: -------------------------------------------------------------------------------- 1 | # `SerialDisposable` class # 2 | 3 | Represents a disposable resource whose underlying disposable resource can be replaced by another disposable resource, causing automatic disposal of the previous underlying disposable resource. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of a `SerialDisposable`. 8 | 9 | ```js 10 | const serialDisposable = new SerialDisposable(); 11 | 12 | const d1 = Disposable.create(() => console.log('one')); 13 | 14 | serialDisposable.setDisposable(d1); 15 | 16 | const d2 = Disposable.create(() => console.log('two')); 17 | 18 | serialDisposable.setDisposable(d2); 19 | // => one 20 | 21 | serialDisposable.dispose(); 22 | // = two 23 | ``` 24 | 25 | ## `SerialDisposable` Constructor ## 26 | - [`constructor`](#serialdisposable) 27 | 28 | ## `SerialDisposable` Instance Methods ## 29 | - [`dispose`](#serialdisposableprototypedispose) 30 | - [`getDisposable`](#serialdisposableprototypegetdisposable) 31 | - [`setDisposable`](#serialdisposableprototypesetdisposable) 32 | 33 | ## `SerialDisposable` Instance Properties ## 34 | - [`isDisposed`](#isdisposed) 35 | 36 | ## _SerialDisposable Constructor_ ## 37 | 38 | ### `SerialDisposable()` 39 | 40 | Initializes a new instance of the `SerialDisposable` class. 41 | 42 | #### Example 43 | ```js 44 | const serialDisposable = new SerialDisposable(); 45 | 46 | console.log(serialDisposable.isDisposed); 47 | // => false 48 | ``` 49 | 50 | * * * 51 | 52 | ## _SerialDisposable Instance Methods_ ## 53 | 54 | ### `SerialDisposable.prototype.dispose()` 55 | 56 | Disposes the underlying disposable as well as all future replacements. 57 | 58 | #### Example 59 | 60 | ```js 61 | const serialDisposable = new SerialDisposable(); 62 | 63 | const d1 = Disposable.create(() => console.log('one')); 64 | 65 | serialDisposable.setDisposable(d1); 66 | 67 | serialDisposable.dispose(); 68 | // => one 69 | ``` 70 | 71 | * * * 72 | 73 | ### `SerialDisposable.prototype.getDisposable()` 74 | 75 | Gets the underlying disposable. 76 | 77 | #### Returns 78 | `Disposable` - The underlying disposable. 79 | 80 | #### Example 81 | 82 | ```js 83 | const serialDisposable = new SerialDisposable(); 84 | 85 | const d1 = Disposable.create(() => console.log('one')); 86 | 87 | serialDisposable.setDisposable(d1); 88 | 89 | console.log(serialDisposable.getDisposable() === d1); 90 | // => true 91 | ``` 92 | 93 | * * * 94 | 95 | ### `SerialDisposable.prototype.setDisposable(value)` 96 | 97 | Sets the underlying disposable. 98 | 99 | #### Arguments 100 | 1. `value` `Disposable`: The new underlying disposable. 101 | 102 | #### Example 103 | 104 | ```js 105 | const serialDisposable = new SerialDisposable(); 106 | 107 | const d1 = Disposable.create(() => console.log('one')); 108 | 109 | serialDisposable.setDisposable(d1); 110 | 111 | serialDisposable.dispose(); 112 | // => one 113 | 114 | const d2 = Disposable.create(() => console.log('two')); 115 | 116 | serialDisposable.setDisposable(d2); 117 | // => two 118 | ``` 119 | 120 | * * * 121 | 122 | ## _SerialDisposable Instance Properties_ ## 123 | 124 | ### `isDisposed` 125 | 126 | Gets a value that indicates whether the object is disposed. 127 | 128 | #### Example 129 | ```js 130 | const serialDisposable = new SerialDisposable(); 131 | 132 | const d1 = Disposable.create(() => console.log('one')); 133 | 134 | serialDisposable.setDisposable(d1); 135 | 136 | console.log(serialDisposable.isDisposed); 137 | // => false 138 | 139 | serialDisposable.dispose(); 140 | // => one 141 | 142 | console.log(serialDisposable.isDisposed); 143 | // => true 144 | ``` 145 | 146 | * * * 147 | -------------------------------------------------------------------------------- /doc/singleassignmentdisposable.md: -------------------------------------------------------------------------------- 1 | # `SingleAssignmentDisposable` class # 2 | 3 | Represents a disposable resource which only allows a single assignment of its underlying disposable resource. If an underlying disposable resource has already been set, future attempts to set the underlying disposable resource will throw an Error. 4 | 5 | ## Usage ## 6 | 7 | The follow example shows the basic usage of a `SingleAssignmentDisposable`. 8 | 9 | ```js 10 | const singleDisposable = new SingleAssignmentDisposable(); 11 | 12 | const disposable = Disposable.create(() => console.log('disposed')); 13 | 14 | singleDisposable.setDisposable(disposable); 15 | 16 | singleDisposable.dispose(); 17 | // => disposed 18 | ``` 19 | 20 | ## `SingleAssignmentDisposable Constructor` ## 21 | - [`constructor`](#singleassignmentdisposable) 22 | 23 | ## `SingleAssignmentDisposable Instance Methods` ## 24 | - [`dispose`](#singleassignmentdisposableprototypedispose) 25 | - [`getDisposable`](#singleassignmentdisposableprototypegetdisposable) 26 | - [`setDisposable`](#singleassignmentdisposableprototypesetdisposable) 27 | 28 | ## `SingleAssignmentDisposable Instance Properties` ## 29 | - [`isDisposed`](#isdisposed) 30 | 31 | ## _SingleAssignmentDisposable Constructor_ ## 32 | 33 | ### `SingleAssignmentDisposable()` 34 | 35 | Initializes a new instance of the `SingleAssignmentDisposable` class. 36 | 37 | #### Example 38 | ```js 39 | const singleDisposable = new SingleAssignmentDisposable(); 40 | 41 | console.log(singleDisposable.isDisposed); 42 | // => false 43 | ``` 44 | 45 | * * * 46 | 47 | ## _SingleAssignmentDisposable Instance Methods_ ## 48 | 49 | ### `SingleAssignmentDisposable.prototype.dispose()` 50 | 51 | Disposes the underlying disposable. 52 | 53 | #### Example 54 | 55 | ```js 56 | const singleDisposable = new SingleAssignmentDisposable(); 57 | 58 | const disposable = Disposable.create(() => console.log('disposed')); 59 | 60 | singleDisposable.setDisposable(disposable); 61 | 62 | console.log(singleDisposable.isDisposed); 63 | // => false 64 | 65 | singleDisposable.dispose(); 66 | // => disposed 67 | 68 | console.log(singleDisposable.isDisposed); 69 | // => true 70 | ``` 71 | 72 | * * * 73 | 74 | ### `SingleAssignmentDisposable.prototype.getDisposable()` 75 | 76 | Gets the underlying disposable. After disposal, the result of getting this method is undefined. 77 | 78 | #### Returns 79 | `Disposable` - The underlying disposable. 80 | 81 | #### Example 82 | 83 | ```js 84 | const singleDisposable = new SingleAssignmentDisposable(); 85 | 86 | const disposable = Disposable.create(() => console.log('disposed')); 87 | 88 | singleDisposable.setDisposable(disposable); 89 | 90 | console.log(singleDisposable.getDisposable() === disposable); 91 | ``` 92 | 93 | * * * 94 | 95 | ### `SingleAssignmentDisposable.prototype.setDisposable(value)` 96 | 97 | Sets the underlying disposable. 98 | 99 | #### Arguments 100 | 1. `value`: `Disposable`: The new underlying disposable. 101 | 102 | #### Example 103 | 104 | ```js 105 | const singleDisposable = new SingleAssignmentDisposable(); 106 | 107 | const d1 = Disposable.create(() => console.log('one')); 108 | 109 | singleDisposable.setDisposable(d1); 110 | 111 | const d2 = Disposable.create(() => console.log('two')); 112 | 113 | try { 114 | singleDisposable.setDisposable(d2); 115 | } catch (e) { 116 | console.log(e.message); 117 | } 118 | 119 | // => Disposable has already been assigned 120 | ``` 121 | 122 | * * * 123 | 124 | ## _SingleAssignmentDisposable Instance Properties_ ## 125 | 126 | ### `isDisposed` 127 | 128 | Gets a value that indicates whether the object is disposed. 129 | 130 | #### Example 131 | ```js 132 | const singleDisposable = new SingleAssignmentDisposable(); 133 | 134 | const disposable = Disposable.create(() => console.log('disposed')); 135 | 136 | singleDisposable.setDisposable(disposable); 137 | 138 | console.log(singleDisposable.isDisposed); 139 | // => false 140 | 141 | singleDisposable.dispose(); 142 | // => disposed 143 | 144 | console.log(singleDisposable.isDisposed); 145 | // => true 146 | ``` 147 | 148 | * * * 149 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | BinaryDisposable: require('./binarydisposable'), 5 | CompositeDisposable: require('./compositedisposable'), 6 | Disposable: require('./disposable'), 7 | NAryDisposable: require('./narydisposable'), 8 | RefCountDisposable: require('./refcountdisposable'), 9 | SerialDisposable: require('./serialdisposable'), 10 | SingleAssignmentDisposable: require('./singleassignmentdisposable') 11 | }; 12 | -------------------------------------------------------------------------------- /narydisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Represents a group of disposable resources that are disposed together. 5 | * @constructor 6 | * Creates a new group of disposable resources that are disposed together. 7 | * @param [Any] disposables Disposable resources to add to the group. 8 | */ 9 | function NAryDisposable(disposables) { 10 | this._disposables = disposables; 11 | this.isDisposed = false; 12 | } 13 | 14 | /** 15 | * Disposes all disposables in the group. 16 | */ 17 | NAryDisposable.prototype.dispose = function () { 18 | if (!this.isDisposed) { 19 | this.isDisposed = true; 20 | for (var i = 0, len = this._disposables.length; i < len; i++) { 21 | this._disposables[i].dispose(); 22 | } 23 | this._disposables.length = 0; 24 | } 25 | }; 26 | 27 | module.exports = NAryDisposable; 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rx.disposables", 3 | "version": "1.0.0", 4 | "description": "Library for Disposables which can be used independently from RxJS", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tape test/**/*.js | tap-spec && markdown-doctest" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Reactive-Extensions/rx.disposables.git" 12 | }, 13 | "keywords": [ 14 | "Rx", 15 | "RxJS", 16 | "Disposables" 17 | ], 18 | "author": "Microsoft Corporation", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/Reactive-Extensions/rx.disposables/issues" 22 | }, 23 | "homepage": "https://github.com/Reactive-Extensions/rx.disposables#readme", 24 | "devDependencies": { 25 | "markdown-doctest": "^0.3.0", 26 | "tap-spec": "^4.1.1", 27 | "tape": "^4.4.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /refcountdisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Disposable = require('./disposable'); 4 | 5 | function InnerDisposable(disposable) { 6 | this._disposable = disposable; 7 | } 8 | 9 | InnerDisposable.prototype.dispose = function () { 10 | var temp = this._disposable; 11 | this._disposable = null; 12 | temp && temp._release(); 13 | }; 14 | 15 | /** 16 | * Represents a disposable resource that only disposes its underlying disposable resource when all dependent disposable objects have been disposed. 17 | */ 18 | function RefCountDisposable(disposable) { 19 | this._disposable = disposable; 20 | this.isDisposed = false; 21 | this._isPrimaryDisposed = false; 22 | this._count = 0; 23 | } 24 | 25 | /** 26 | * Disposes the underlying disposable only when all dependent disposables have been disposed 27 | */ 28 | RefCountDisposable.prototype.dispose = function () { 29 | if (!this.isDisposed && !this._isPrimaryDisposed) { 30 | this._isPrimaryDisposed = true; 31 | if (this._count === 0) { 32 | this.isDisposed = true; 33 | this._disposable.dispose(); 34 | this._disposable = null; 35 | this.isDisposed = true; 36 | } 37 | } 38 | }; 39 | 40 | RefCountDisposable.prototype._release = function () { 41 | if (this._disposable) { 42 | this._count--; 43 | if (this._isPrimaryDisposed && this._count === 0) { 44 | this._disposable.dispose(); 45 | this._disposable = null; 46 | this.isDisposed = true; 47 | } 48 | } 49 | }; 50 | 51 | /** 52 | * Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable. 53 | * @returns {Disposable} A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime. 54 | */ 55 | RefCountDisposable.prototype.getDisposable = function () { 56 | if (this.isDisposed) { 57 | return Disposable.empty; 58 | } else { 59 | this._count++; 60 | return new InnerDisposable(this); 61 | } 62 | }; 63 | 64 | module.exports = RefCountDisposable; 65 | -------------------------------------------------------------------------------- /serialdisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @constructor 5 | * Represents a disposable resource whose underlying disposable resource can 6 | * be replaced by another disposable resource, causing automatic disposal of 7 | * the previous underlying disposable resource. 8 | */ 9 | function SerialDisposable() { 10 | this.isDisposed = false; 11 | this._current = null; 12 | } 13 | 14 | /** 15 | * Gets the underlying disposable. 16 | * @returns {Any} the underlying disposable. 17 | */ 18 | SerialDisposable.prototype.getDisposable = function () { 19 | return this._current; 20 | }; 21 | 22 | SerialDisposable.prototype.setDisposable = function (value) { 23 | var shouldDispose = this.isDisposed; 24 | if (!shouldDispose) { 25 | var old = this._current; 26 | this._current = value; 27 | old && old.dispose(); 28 | } 29 | 30 | shouldDispose && value && value.dispose(); 31 | }; 32 | 33 | /** Performs the task of cleaning up resources. */ 34 | SerialDisposable.prototype.dispose = function () { 35 | if (!this.isDisposed) { 36 | this.isDisposed = true; 37 | var old = this._current; 38 | this._current = null; 39 | old && old.dispose(); 40 | } 41 | }; 42 | 43 | module.exports = SerialDisposable; 44 | -------------------------------------------------------------------------------- /singleassignmentdisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @constructor 5 | * Represents a disposable resource which only allows a single assignment of 6 | * its underlying disposable resource. If an underlying disposable resource has 7 | * already been set, future attempts to set the underlying disposable resource 8 | * will throw an Error. 9 | */ 10 | function SingleAssignmentDisposable () { 11 | this.isDisposed = false; 12 | this._current = null; 13 | } 14 | 15 | /** 16 | * Gets the underlying disposable. After disposal, the result of getting 17 | * this method is null. 18 | * @returns {Any} the underlying disposable. 19 | */ 20 | SingleAssignmentDisposable.prototype.getDisposable = function () { 21 | return this._current; 22 | }; 23 | 24 | /** 25 | * Sets the underlying disposable. Throws an error if the 26 | * SingleAssignmentDisposable has already been assigned to. 27 | * @param {Any} value the underlying disposable to set. 28 | */ 29 | SingleAssignmentDisposable.prototype.setDisposable = function (value) { 30 | if (this._current) { throw new Error('Disposable has already been assigned'); } 31 | var shouldDispose = this.isDisposed; 32 | !shouldDispose && (this._current = value); 33 | shouldDispose && value && value.dispose(); 34 | }; 35 | 36 | /** Performs the task of cleaning up resources. */ 37 | SingleAssignmentDisposable.prototype.dispose = function () { 38 | if (!this.isDisposed) { 39 | this.isDisposed = true; 40 | var old = this._current; 41 | this._current = null; 42 | old && old.dispose(); 43 | } 44 | }; 45 | 46 | module.exports = SingleAssignmentDisposable; 47 | -------------------------------------------------------------------------------- /test/binarydisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var Disposable = require('../disposable'); 5 | var BinaryDisposable = require('../binarydisposable'); 6 | 7 | test('BinaryDisposable#constructor', function (t) { 8 | var disp1 = false; 9 | var disp2 = false; 10 | 11 | var d1 = Disposable.create(function () { disp1 = true; }); 12 | var d2 = Disposable.create(function () { disp2 = true; }); 13 | 14 | var b = new BinaryDisposable(d1, d2); 15 | 16 | t.equal(b.isDisposed, false, 'should not be disposed'); 17 | t.equal(disp1, false, 'first should not be disposed'); 18 | t.equal(disp2, false, 'second should not be disposed'); 19 | 20 | t.end(); 21 | }); 22 | 23 | test('BinaryDisposable#dispose', function (t) { 24 | var disp1 = false; 25 | var disp2 = false; 26 | 27 | var d1 = Disposable.create(function () { disp1 = true; }); 28 | var d2 = Disposable.create(function () { disp2 = true; }); 29 | 30 | var b = new BinaryDisposable(d1, d2); 31 | 32 | t.equal(b.isDisposed, false, 'should not be disposed'); 33 | t.equal(disp1, false, 'first should not be disposed'); 34 | t.equal(disp2, false, 'second should not be disposed'); 35 | 36 | b.dispose(); 37 | 38 | t.equal(b.isDisposed, true, 'should be disposed'); 39 | t.equal(disp1, true, 'first should be disposed'); 40 | t.equal(disp2, true, 'second should be disposed'); 41 | 42 | b.dispose(); 43 | 44 | t.equal(b.isDisposed, true, 'should be idempotent'); 45 | t.equal(disp1, true, 'first should be idempotent'); 46 | t.equal(disp2, true, 'second should be idempotent'); 47 | 48 | t.end(); 49 | }); 50 | -------------------------------------------------------------------------------- /test/disposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var Disposable = require('../disposable'); 5 | 6 | test('Disposable#create', function (t) { 7 | var disposable = Disposable.create(function () { }); 8 | t.ok(disposable, 'disposable should not be undefined'); 9 | t.end(); 10 | }); 11 | 12 | test('Disposable#dispose', function (t) { 13 | var disposed = false; 14 | var d = Disposable.create(function () { disposed = true; }); 15 | 16 | t.ok(!disposed, 'should not be disposed'); 17 | d.dispose(); 18 | t.ok(disposed, 'should be disposed'); 19 | t.end(); 20 | }); 21 | 22 | test('Disposable#empty', function (t) { 23 | var d = Disposable.empty; 24 | t.ok(d, 'should not be null'); 25 | d.dispose(); 26 | t.end(); 27 | }); 28 | -------------------------------------------------------------------------------- /test/narydisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var Disposable = require('../disposable'); 5 | var NAryDisposable = require('../narydisposable'); 6 | 7 | test('NAryDisposable#constructor', function (t) { 8 | var disp1 = false; 9 | var disp2 = false; 10 | var disp3 = false; 11 | 12 | var d1 = Disposable.create(function () { disp1 = true; }); 13 | var d2 = Disposable.create(function () { disp2 = true; }); 14 | var d3 = Disposable.create(function () { disp3 = true; }); 15 | 16 | var b = new NAryDisposable([d1, d2, d3]); 17 | 18 | t.equal(b.isDisposed, false, 'should not be disposed'); 19 | t.equal(disp1, false, 'first should not be disposed'); 20 | t.equal(disp2, false, 'second should not be disposed'); 21 | t.equal(disp3, false, 'third should not be disposed'); 22 | 23 | t.end(); 24 | }); 25 | 26 | test('NAryDisposable#dispose', function (t) { 27 | var disp1 = false; 28 | var disp2 = false; 29 | var disp3 = false; 30 | 31 | var d1 = Disposable.create(function () { disp1 = true; }); 32 | var d2 = Disposable.create(function () { disp2 = true; }); 33 | var d3 = Disposable.create(function () { disp3 = true; }); 34 | 35 | var b = new NAryDisposable([d1, d2, d3]); 36 | 37 | t.equal(b.isDisposed, false, 'should not be disposed'); 38 | t.equal(disp1, false, 'first should not be disposed'); 39 | t.equal(disp2, false, 'second should not be disposed'); 40 | t.equal(disp1, false, 'third should not be disposed'); 41 | 42 | b.dispose(); 43 | 44 | t.equal(b.isDisposed, true, 'should be disposed'); 45 | t.equal(disp1, true, 'first should be disposed'); 46 | t.equal(disp2, true, 'second should be disposed'); 47 | t.equal(disp2, true, 'third should be disposed'); 48 | 49 | b.dispose(); 50 | 51 | t.equal(b.isDisposed, true, 'should be idempotent'); 52 | t.equal(disp1, true, 'first should be idempotent'); 53 | t.equal(disp2, true, 'second should be idempotent'); 54 | t.equal(disp2, true, 'third should be idempotent'); 55 | 56 | t.end(); 57 | }); 58 | -------------------------------------------------------------------------------- /test/refcountdisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var RefCountDisposable = require('../refcountdisposable'); 5 | 6 | function BooleanDisposable() { 7 | this.isDisposed = false; 8 | } 9 | 10 | BooleanDisposable.prototype.dispose = function () { 11 | !this.isDisposed && (this.isDisposed = true); 12 | }; 13 | 14 | test('RefCountDisposable single reference', function (t) { 15 | var d = new BooleanDisposable(); 16 | var r = new RefCountDisposable(d); 17 | t.notOk(d.isDisposed, 'should not be disposed'); 18 | r.dispose(); 19 | t.ok(d.isDisposed, 'should be disposed'); 20 | r.dispose(); 21 | t.ok(d.isDisposed, 'should still be disposed'); 22 | 23 | t.end(); 24 | }); 25 | 26 | test('RefCountDisposable ref counting', function (t) { 27 | var d = new BooleanDisposable(); 28 | var r = new RefCountDisposable(d); 29 | t.notOk(d.isDisposed, 'should not be disposed'); 30 | 31 | var d1 = r.getDisposable(); 32 | var d2 = r.getDisposable(); 33 | t.notOk(d.isDisposed, 'after two getDisposable() calls should not be disposed'); 34 | 35 | d1.dispose(); 36 | t.notOk(d.isDisposed, 'after one dispose() should not be disposed'); 37 | 38 | d2.dispose(); 39 | t.notOk(d.isDisposed, 'after two dispose() should be disposed'); 40 | 41 | r.dispose(); 42 | t.ok(d.isDisposed, 'the outer should be disposed'); 43 | t.ok(r.isDisposed, 'the ref counted should be disposed'); 44 | 45 | var d3 = r.getDisposable(); // CHECK 46 | d3.dispose(); 47 | 48 | t.end(); 49 | }); 50 | 51 | test('RefCountDisposable primary disposes first', function (t) { 52 | var d = new BooleanDisposable(); 53 | var r = new RefCountDisposable(d); 54 | t.notOk(d.isDisposed, 'should not be disposed after creation'); 55 | 56 | var d1 = r.getDisposable(); 57 | var d2 = r.getDisposable(); 58 | t.notOk(d.isDisposed, 'should not be disposed after two getDisposable() calls'); 59 | 60 | d1.dispose(); 61 | t.notOk(d.isDisposed, 'should not be disposed after one dispose() call'); 62 | 63 | r.dispose(); 64 | t.notOk(d.isDisposed, 'should not dispose outer if inner has refs'); 65 | 66 | d2.dispose(); 67 | t.ok(d.isDisposed, 'should dispose outer if dispose() called twice'); 68 | 69 | t.end(); 70 | }); 71 | -------------------------------------------------------------------------------- /test/serialdisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var SerialDisposable = require('../serialdisposable'); 5 | var Disposable = require('../disposable'); 6 | 7 | 8 | test('SerialDisposable#constructor', function (t) { 9 | var m = new SerialDisposable(); 10 | 11 | t.ok(!m.getDisposable(), 'should not have a disposable'); 12 | 13 | t.end(); 14 | }); 15 | 16 | test('SerialDisposable replace before dispose()', function (t) { 17 | var disp1 = false; 18 | var disp2 = false; 19 | 20 | var m = new SerialDisposable(); 21 | 22 | var d1 = Disposable.create(function () { disp1 = true; }); 23 | m.setDisposable(d1); 24 | 25 | t.equal(d1, m.getDisposable(), 'should have a disposable set'); 26 | t.ok(!disp1, 'should not be disposed'); 27 | 28 | var d2 = Disposable.create(function () { disp2 = true; }); 29 | m.setDisposable(d2); 30 | 31 | t.equal(d2, m.getDisposable(), 'should have a new disposable set'); 32 | t.ok(disp1, 'first should be disposed'); 33 | t.ok(!disp2, 'next should not be disposed'); 34 | 35 | t.end(); 36 | }); 37 | 38 | test('SerialDisposable replace after dispose', function (t) { 39 | var disp1 = false; 40 | var disp2 = false; 41 | 42 | var m = new SerialDisposable(); 43 | m.dispose(); 44 | 45 | var d1 = Disposable.create(function () { disp1 = true; }); 46 | m.setDisposable(d1); 47 | 48 | t.equal(null, m.getDisposable(), 'should not have a set disposable after dispose'); 49 | t.ok(disp1, 'should be disposed'); 50 | 51 | var d2 = Disposable.create(function () { disp2 = true; }); 52 | m.setDisposable(d2); 53 | 54 | t.equal(null, m.getDisposable(), 'should not have a set disposable after dispose'); 55 | t.ok(disp2, 'should be disposed'); 56 | 57 | t.end(); 58 | }); 59 | 60 | test('SerialDisposable#dispose', function (t) { 61 | var disp = false; 62 | 63 | var m = new SerialDisposable(); 64 | var d = Disposable.create(function () { disp = true; }); 65 | m.setDisposable(d); 66 | 67 | t.equal(d, m.getDisposable(), 'should have set the disposable'); 68 | t.ok(!disp, 'should not be disposed before dispose()'); 69 | 70 | m.dispose(); 71 | 72 | t.ok(disp, 'should be disposed after dispose()'); 73 | t.equal(null, m.getDisposable(), 'should clear the current disposable'); 74 | 75 | t.end(); 76 | }); 77 | -------------------------------------------------------------------------------- /test/singleassignmentdisposable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape'); 4 | var SingleAssignmentDisposable = require('../singleassignmentdisposable'); 5 | var Disposable = require('../disposable'); 6 | 7 | test('SingleAssignmentDisposable setDisposable null', function (t) { 8 | var d = new SingleAssignmentDisposable(); 9 | 10 | d.setDisposable(null); 11 | 12 | t.equal(null, d.getDisposable(), 'getDisposable should return null'); 13 | 14 | t.end(); 15 | }); 16 | 17 | test('SingleAssignmentDisposable dispose after set', function (t) { 18 | var disposed = false, 19 | d = new SingleAssignmentDisposable(), 20 | dd = Disposable.create(function () { disposed = true; }); 21 | 22 | d.setDisposable(dd); 23 | t.equal(dd, d.getDisposable(), 'should have set the disposable via setDisposable'); 24 | t.ok(!disposed, 'should not be disposed'); 25 | 26 | d.dispose(); 27 | t.ok(disposed, 'should be disposed after dispose()'); 28 | 29 | d.dispose(); 30 | t.ok(disposed, 'should be idempotent after dispose()'); 31 | 32 | t.end(); 33 | }); 34 | 35 | test('SingleAssignmentDisposable dispose before setDisposable', function (t) { 36 | var disposed = false, 37 | d = new SingleAssignmentDisposable(), 38 | dd = Disposable.create(function () { disposed = true; }); 39 | t.ok(!disposed, 'should not be disposed'); 40 | 41 | d.dispose(); 42 | t.ok(!disposed, 'should not be disposed after disposed'); 43 | 44 | d.setDisposable(dd); 45 | t.ok(d.getDisposable() == null, 'should not set disposable'); 46 | t.ok(disposed, 'should be disposed after setDisposable'); 47 | 48 | d.dispose(); 49 | t.ok(disposed, 'calling dispose should dispose idempotent'); 50 | 51 | t.end(); 52 | }); 53 | --------------------------------------------------------------------------------