New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

laissez-faire

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

laissez-faire - npm Package Compare versions

Comparing version 0.4.1 to 0.6.0

2

component.json

@@ -5,3 +5,3 @@ {

"description": "A Promises/A implementation i.e a \"thenable\"",
"version": "0.4.1",
"version": "0.6.0",
"keywords": ["promise", "async", "future", "control", "flow"],

@@ -8,0 +8,0 @@ "dependencies": {},

@@ -6,3 +6,3 @@ var fs = require('fs'),

.include('src/')
.set('debug', true)
.set('debug', false)
.main('src/index')

@@ -18,2 +18,4 @@ .export('Promise')

.include('tests/')
.include('node_modules/promise-tests/lib/tests/')
.include('src/')
.exclude(/browser-built\.js$/)

@@ -20,0 +22,0 @@ .replace({

{
"name": "laissez-faire",
"version": "0.4.1",
"version": "0.6.0",
"description": "A promise implementation. Simple and fast",

@@ -12,7 +12,9 @@ "main": "src/index.js",

"mocha": "*",
"sinon": "*"
"sinon": "*",
"chai": "*",
"promise-tests": ""
},
"scripts" : {
"build": "node ./glue.js",
"test": "node ./tests/"
"test": "node tests/"
},

@@ -19,0 +21,0 @@ "repository": {

@@ -1,1 +0,1 @@

# Laissez-faire It works in [node](./src/index.js) and the [browser](./browser/Promise.js). Anything in the name? Yea its a French word meaning "let it be". Seemed apt for a library designed to eliminate the need to worry about when computation occurs. ## Differences from other libraries Laissez-faire is compliant with the [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) spec as far as I understand it. However, it does break from some patterns which are common in other implementations: 1. The only way to reject a promise is with an Error instance. Even if you call `reject`. This means you don't need to throw errors, you can return them with the exact same effect. Also it means you only need to use one method to complete a promise (take your pick from `reject`, `resolve`, or `assign`). I use assign because it reflects the way I think of promises; which is as super variables. 2. Doesn't guarantee async calls to `then`; you use promises to abstract away the effects of time. Therefore, there shouldn't be any need to guarantee anything about when promises will be fulfilled. The reasoning behind this feature is usually that it makes promises easier to understand for beginners. I think its more like this feature makes it easier for users to misunderstand promises and treat them like a less ugly version of the callback pattern found in Node. 3. Paranoia is optional; a goblin proof proxy object is not created when you create a new instance of laissez. If you want to be able to pass out access to your promises value without allowing them to also assign a value to your promise you call `promise.proxy()` A new proxy is generated with each call so you can pass out as many as you like. 4. API: 1. `new Laissez` instead of `lib.defer()` or `defer()` 2. `deffered.reject(new Error)` instead of `deferred.reject('any value')` 3. `deferred.proxy()` instead of `deferred.promise` As a result of the different error handling semantics Laissez-faire fails many of the common tests found in the [promises test suite](https://github.com/domenic/promise-tests) written by Domenic Denicola. It comes with a lightly modified version of the promises test suite as well as a few extra suites for Laissez-faire specific features. ## Performance [Good](https://github.com/jkroso/promise-perf-tests) it seems. ```javascript ==================================== Test: defer-create x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 1 0.0001 - when 19 0.0019 1800.00 rsvp 35 0.0035 3400.00 deferred 40 0.0040 3900.00 q 453 0.0453 45200.00 ==================================== Test: promise-fulfill x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 7 0.0007 - when 9 0.0009 28.57 deferred 12 0.0012 71.43 rsvp 86 0.0086 1128.57 q 215 0.0215 2971.43 ==================================== Test: promise-reject x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 13 0.0013 - when 67 0.0067 415.38 rsvp 138 0.0138 961.54 deferred 162 0.0162 1146.15 q 279 0.0279 2046.15 ==================================== Test: promise-sequence x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 15 0.0015 - deferred 38 0.0038 153.33 when 41 0.0041 173.33 rsvp 222 0.0222 1380.00 q 4634 0.4634 30793.33 ``` ### What makes it better 1. Smaller 2. Faster 3. Simpler error semantics 4. Easier to debug (uncaught errors are logged) 5. Flexible API ### What makes it worse 1. Not a dropin replacement for many other libraries. (it should interope fine though) ## API ```javascript var Promise = require('laissez-faire') var promise = new Promise ``` * __promise.then(done, success)__ * __promise.end(done, success)__ * __promise.resolve(value)__ * __promise.success(value)__ * __promise.fail(value)__ * __promise.reject(error)__ * __promise.assign(value|error)__ * __promise.proxy()__ Handle uncaught errors just set `Promise.prepareException = function (failingPromise, error) {}` And to cancel the logic you set in motion set `Promise.cancelException = function (noLongerfailingPromise) {}` ## Basic Usage ```javascript var promise = new Promise(); promise.then(function(value) { // success }, function(value) { // failure }); // later... promise.resolve(value) // triggers first callback // or... promise.reject(error) // triggers second callback ``` Once a promise has been resolved or rejected, it cannot be resolved or rejected again. Here is an example of a simple XHR2 wrapper written using `Laissez-faire`: ```javascript var getJSON = function(url) { var promise = new Promise() var client = new XMLHttpRequest() client.open("GET", url) client.onreadystatechange = handler client.responseType = "json" client.setRequestHeader("Accept", "application/json") client.send() function handler() { if (this.readyState === this.DONE) { if (this.status === 200) promise.resolve(this.response) else promise.reject(this) } }; return promise; }; getJSON("/posts.json").then(function(json) { // continue }, function(error) { // handle errors }); ``` ## Understanding promises I struggled to understand promises and that is why I started playing with this project. It would be rude of me not to share my learnings. I hope my explanation prevents you from needing to take the same route in order to understand them. Every explanation I have read begins like this: "A promise represents the eventual value returned from the single completion of an operation". I have read a few and they all sounded suspiciously wrote. That one was from the Promises/A spec. Its a shame they all choose to use the word "eventual" since it is actually slightly misleading. Promises may be resolved now. Therefore, a simpler and more accurate way of introducing promises would be to say "A promise represents the value of a computation". This of course would raise the question: isn't that was variables are for? Yes that is what variables are for. Except variables break if the computation occurs at any time other than right now. And now you see the problem they are designed to solve. Promises allow you to not care when the computation occurs just that it does. In order to do this they need to do two things. 1. Store the result of the computation as soon as it happens 2. Provide a mechanism to connect further computations on this value By providing these capabilities they allow you to ignore the timing of computation completely. They could easily become a language feature complimenting the less powerful variable. You saw promises in use in the previous section but lets walk through how they are used since they look nothing like variables syntactically. First we create the promise: `var promise = new Promise`. So we need to use a variable in order to use a promise. You could say then that we are creating an enhanced variable. Then we do some computation and assign our value to the promise `return promise.assign('some value')`. Note you must always `return` the promise now though you don't have to assign to it until you are good and ready. So your computations must know how to manage a promise, as shame since semantically they aren't much different from variables, though blame that one on the language designers. Maybe one day JavaScript will be inspired and adopt message passing like Io and Smalltalk, maybe. Lets see if we can visualize a program written synchronously and contrast it with one using promises in place of variables. Then lets look at one using callbacks. Lets perform a sequence of additions on unknown values. In summary promises are a way of storing and accessing values devoid of when. That makes them very useful for situations where you can't be certain something is going to be sitting in memory ready to go but would like to take advantage of the speed if it is. Callbacks enable this and will always be faster, however promises provide the value and error propagation infrastructure to make these programs easier to reason about. Plus implementations like `Laissez-faire` are actually fairly light weight so offer good bang for your buck. The time they save you can coding be spent optimizing algorithms. __Sync only:__ ```javascript var a = {}, b = 2 try { // var c = a + b throw new Error } catch (e) { c = 0 } c += 1 console.log(c) ``` Note: JavaScript won't throw an error when adding an object and a number like I though when I first wrote the example so we are throwing one manually. __Timing irrelevant (with promises):__ ```javascript var a = new Promise().assign({}), b = new Promise().assign(2), c = a .then(function(a){ return b.then(function(b) { // return a + b return new Error }) }) .then(null, function(e) { return 0 }) .then(function (c) { return c + 1 }) .then(console.log.bind(console)) ``` Here we assigned values to the promises immediately, and therefore, the subsequent computations were run immediately. However, if it took all year for their values to be computed that would be fine. The first operation actually returns a promise. This is fine since when `Laissez-faire` see a promise being resolved with a promise it is smart enough to know not to take this literally and will instead fetch the value from the returned promise before resolving for real. In JavaScript the + operator returns a value instantly though the above code would work fine if it was to return a promise and take its sweet time doing the actual operation. __Timing irrelevant (with callbacks):__ ```javascript var c getA(function(a){ getB(function(b){ try { // c = a + b throw new Error } catch (e) { c = 0 } c.plus(1, console.log.bind(console)) })) }) ``` Notice: that we used a plus method with a callback. Since that for this entire operation to be free from the need for instant operation every operation must be async/sync safe. It still depends on the assignment operation being done instantly however. ## Chaining If you return a regular value, it will be passed, as is, to the next handler. ```javascript getJSON("/posts.json") .then(function(json) { return json.post }) .then(function(post) { // proceed }); ``` Returned promises are recognized as promises and have their resolved value is used to resolve the promise they were returned to ```javascript getJSON("/post/1.json") .then(function(post) { // save off post return getJSON(post.commentURL) }) .then(function(comments) { // proceed with access to posts and comments }) ``` ## Error Handling Errors also propagate: ```javascript getJSON("/badurl.json") .then(function(posts) { }) .then(null, function(error) { // even though no error callback was passed to the // first `.then`, the error propagates }) ``` Technically a promise can never throw an error since at any time in the future a user could add a child promise and handle the exception. However in practice the promise user will bind their error handlers immediately, so in most cases unhandled rejections which sit around for more than one tick of the event loop are genuine errors. `Laissez-faire` provides a mechanism for you to hook into these errors. See the source for details. It actually uses this mechanism itself to provide a nice default behavior which is to log the errors to the console after a 1 second delay. If this doesn't suit you then it is easy to override the behavior. ## Finishing with a promise Promises represent values. Like any other value you can never be sure it will never be used again until nobody has access to it. If however you have a promise and you know the next operation you do one it will be your last there is no need to create a chainable promise from it. To allow you to reduce the cost this operation (by a little) `Laissez-faire` provides an `end` method. It will provide the promises value to your callbacks as usual but will not return a new promise. Thereby, saving some computation. We also take advantage of the situation and allow any uncaught errors to blow up since we know you have no plans of catching them. Furthermore, `end` will return `this` thereby allowing a jquery style use of promises which is nice where appropriate. ```javascript var p = new Promise().assign(1) .end(function(val){ // val === 1 return val + 1 }) .end(function(val){ // val === 1 return val + 1 }) .end(function(val){ // this error will not be caught throw new Error }) .then(function(val){ // val === 1 return val + 1 }, function(){ // will not handle exception since it is on another branch }) .then(function(val){ // finally val === 2 console.log(val) }) ``` I'd be surprised if that code sample conjured the picture in your head I wanted so hear is a diagram illustrating the structure of the process. ![ process ](https://docs.google.com/drawings/pub?id=1MiWhL77a7X457fWy529--ic-pKI9AG1WCmY_pZdENVg&w=960&h=720) Each box represents a process of some kind. The circles below some of the processes represent the values they expose. The first box creates the promise and exposes itself for binding. The three calls to `end` each create a process but don't create new promises. Therefore, any values they might generate are lost. The fourth call, to `then`, does the same thing as the others except it exposes a value to the outside world. This value is represented by a promise, therefore to access it we must use either `then` or `end`. In this case we used `then` which resulting in the final value being exposed. This final value is 2. The flow of data is represented by the arrows with the red boxes showing the value of the data. Hopefully this illustration makes it obvious what is happing when you access the value of a promise via `then` or `end`, you are creating a branch in the process. Values flow down these branches in the same way as errors. Though they are of course handled by separate functions. Because we chose to use `then` as the final call on the fourth branch we will be able to continue processing at any time where we left of. Be that with an error or a value, no matter, so long as the `p` variable doesn't go out of scope. In summary then we can say promises provide a mechanism to freeze process. Ready to defrost and continue via `then` and `end` as soon or as long as you like. ## Generators Promises are often compared to the upcoming JavaScript feature "Generators". It is true that they are the solution to many of the same problems; however, they have very different semantics. Don't get confused by comparisons between the two like I did. Generators are probably closer to event emitters. ## Mutability Its widely considered that promises should be immutable and I agree. I though its interesting to note what happens to promises when they are implemented in a mutable way. So when a promise has its value changed it propagates this value to any child promises. At which point you would of switched to the [Reactive programming](http://en.wikipedia.org/wiki/Reactive_programming) paradigm. The change in implementation to create this effect is trivial. I guess we can say then that promises borderline bring a new paradigm to JavaScript. Its amazing how flexible this language is.
# Laissez-faire Its a promise class. It works in [node](./src/index.js) and the [browser](./browser/Promise.js). Anything in the name? Yea its a French word meaning "let it be". Seemed apt for a library designed to eliminate the need to worry about when computation occurs. ## Differences from other libraries Laissez-faire is compliant with the [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) spec as far as I understand it. However, it does break from some patterns which are common in other implementations: 1. Doesn't guarantee async calls to `then`; you use promises to abstract away the effects of time. Therefore, there shouldn't be any need to guarantee anything about when promises will be fulfilled. The reasoning behind this feature is usually that it makes promises easier to understand for beginners. I think its more like this feature makes it easier for users to misunderstand promises and treat them like a less ugly version of the callback pattern found in Node. 2. Paranoia is optional; a goblin proof proxy object is not created when you create a new instance of laissez. If you want to be able to pass out access to your promises value without allowing them to also assign a value to your promise you call `promise.proxy()` A new proxy is generated with each call so you can pass out as many as you like. 3. API: 1. `new Laissez` instead of `lib.defer()` 2. `deferred.proxy()` instead of `deferred.promise` The test suit is comprised mainly of the [promises test suite](https://github.com/domenic/promise-tests) written by Domenic Denicola. I leave out the always-async test since I disagree with the concept. I have added a few extra suites for Laissez-faire specific features. ## Performance [Good](https://github.com/jkroso/promise-perf-tests) it seems. ```javascript ==================================== Test: defer-create x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 1 0.0001 - when 19 0.0019 1800.00 rsvp 35 0.0035 3400.00 deferred 40 0.0040 3900.00 q 453 0.0453 45200.00 ==================================== Test: promise-fulfill x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 7 0.0007 - when 9 0.0009 28.57 deferred 12 0.0012 71.43 rsvp 86 0.0086 1128.57 q 215 0.0215 2971.43 ==================================== Test: promise-reject x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 13 0.0013 - when 67 0.0067 415.38 rsvp 138 0.0138 961.54 deferred 162 0.0162 1146.15 q 279 0.0279 2046.15 ==================================== Test: promise-sequence x 10000 ------------------------------------ Name Time ms Avg ms Diff % laissez 15 0.0015 - deferred 38 0.0038 153.33 when 41 0.0041 173.33 rsvp 222 0.0222 1380.00 q 4634 0.4634 30793.33 ``` ### What makes it better 1. Smaller 2. Faster 3. Easier to debug (uncaught errors are logged) 4. Flexible API ### What makes it worse 1. I haven't got around to doing any interope testing so will most likely have some bugs if you are passing it promises from other libraries. ## API ```javascript var Promise = require('laissez-faire') var promise = new Promise ``` * __promise.then(done, success)__ * __promise.end(done, success)__ * __promise.resolve(value)__ * __promise.reject(error)__ * __promise.assign(value|error)__ * __promise.fail(value)__ * __promise.success(value)__ * __promise.proxy()__ To handle uncaught errors just set `Promise.prepareException = function (failingPromise, error) {}` And a cenceler `Promise.cancelException = function (noLongerfailingPromise) {}`. In case an exception handler gets added after `prepareException` was called ## Basic Usage ```javascript var promise = new Promise(); promise.then(function(value) { // success }, function(value) { // failure }); // later... promise.resolve(value) // triggers first callback // or... promise.reject(error) // triggers second callback ``` Once a promise has been resolved or rejected, it cannot be resolved or rejected again. Here is an example of a simple XHR2 wrapper written using Laissez-faire: ```javascript var getJSON = function(url) { var promise = new Promise() var client = new XMLHttpRequest() client.open("GET", url) client.onreadystatechange = handler client.responseType = "json" client.setRequestHeader("Accept", "application/json") client.send() function handler() { if (this.readyState === this.DONE) { if (this.status === 200) promise.resolve(this.response) else promise.reject(this) } }; return promise; // or if you you think there might be goblins in your system // return promise.proxy() }; getJSON("/posts.json").then(function(json) { // continue }, function(error) { // handle errors }); ``` ## Understanding promises I struggled to understand promises and that is why I started playing with this project. It would be rude of me not to share my learnings. I hope my explanation prevents you from needing to take the same route in order to understand them. Every explanation I have read begins like this: "A promise represents the eventual value returned from the single completion of an operation". I have read a few and they all sounded suspiciously wrote. That one was from the Promises/A spec. Its a shame they all choose to use the word "eventual" since it is actually slightly misleading. Promises may be resolved now. Therefore, a simpler and more accurate way of introducing promises would be to say "A promise represents the value of a computation". This of course would raise the question: isn't that what variables are for? Yes. Except variables break if the computation occurs at any time other than right now. The problem promises are designed to solve is uncertainty due to the timing of processes. Promises take the worry away. They add some messy syntax but allow you to focus on the process which will ultimatly makes things easier to reason about. In order to do this they need to do two things. 1. Store the result of the computation as soon as it happens 2. Provide a mechanism to connect further computations which depend on this value By providing these capabilities they allow you to ignore the timing of computation completely. They could easily become a language feature complimenting the less powerful variable. You saw promises in use in the previous section but lets walk through how they are used since they look nothing like variables syntactically. First we create the promise: `var promise = new Promise`. So we need to use a variable in order to use a promise. You could say then that we are creating an enhanced variable or more simply a container. Then we do some computation and assign our value to the promise `return promise.assign('some value')`. Note you must always `return` the promise now though you don't have to assign to it until you are good and ready. So your functions must know how to manage a promise, its a shame since semantically they aren't much different from variables, though blame that one on the language designers. Maybe one day JavaScript will be inspired and adopt message passing like Io and Smalltalk, maybe. In summary promises are a way of storing and accessing values devoid of when. That makes them very useful for situations where you can't be certain something is going to be sitting in memory ready to go but would like to take advantage of the speed if it is. Callbacks enable this and will always be faster, however promises provide the value and error propagation infrastructure to make these programs easier to reason about. Plus implementations like Laissez-faire are actually fairly light weight so offer good bang for your buck. The time they save you coding can be spent sleeping at night. <!-- Comparison: Lets explore a few of the ways we can declare process in JS. This example is just addition but includes some errors and error handling. __Sync only:__ ```javascript var a = {}, b = 2 try { // var c = a + b // Should throw but in JS it won't so for the sake of this example we will throw manually throw new Error } catch (e) { c = 0 } c += 1 console.log(c) ``` __With promises:__ ```javascript var a = new Promise().assign({}), b = new Promise().assign(2), c = a .then(function(a){ return b.then(function(b) { // return a + b return new Error }) }) .then(null, function(e) { return 0 }) .then(function (c) { return c + 1 }) .then(console.log.bind(console)) ``` Here we assigned values to the promises immediately, and therefore, the subsequent computations were run immediately. However, if it took all year for their values to be computed that would be fine. The first operation actually returns a promise. This is fine since when Laissez-faire et.al sees a promise being resolved with a promise it is smart enough to know not to take this literally and will instead fetch the value from the returned promise before resolving for real. In JavaScript the + operator returns a value instantly though the above code would work fine if it was to return a promise and take its sweet time doing the actual operation. __With callbacks:__ ```javascript var c getA(function(a){ getB(function(b){ try { // c = a + b throw new Error } catch (e) { c = 0 } c.plus(1, console.log.bind(console)) })) }) ``` Notice: that we used a plus method with a callback. Since that for this entire operation to be free from the need for instant operation every operation must be async/sync safe. It still depends on the assignment operation being done instantly, but I won't make this example any weirder. __With generators:__ ```javascript var gen = (function* () { var a = yeild getA() var b = yeild getB() return a + b }() while (true) { try { gen.next() } catch (e) { c = e.value break } } ``` --> ## Chaining If you return a regular value, it will be passed, as is, to the next handler. ```javascript getJSON("/posts.json") .then(function(json) { return json.post }) .then(function(post) { // proceed }); ``` Returned promises are recognized as promises and have their resolved value used to resolve the promise they were returned to ```javascript getJSON("/post/1.json") .then(function(post) { // save off post return getJSON(post.commentURL) }) .then(function(comments) { // proceed with access to posts and comments }) ``` ## Error Handling Errors also propagate: ```javascript getJSON("/badurl.json") .then(function(posts) { }) .then(null, function(error) { // even though no error callback was passed to the // first `.then`, the error propagates }) ``` Technically a promise can never throw an error since at any time in the future a user could add a child promise and handle the exception. However in practice the promise user will bind their error handlers immediately, so in most cases unhandled rejections which sit around for more than one tick of the event loop are genuine errors. Laissez-faire provides a mechanism for you to hook into these errors. See the source for details. It actually uses this mechanism itself to provide a nice default behavior which is to log the errors to the console after a 1 second delay. If this doesn't suit you then it is easy to override the behavior. ## Finishing with a promise Promises represent values. Like any other value you can never be sure it will never be used again until nobody has access to it. If however you have a promise and you know the next operation you do one it will be your last there is no need to create a chainable promise from it. To allow you to reduce the cost this operation (by a little) Laissez-faire provides an `end` method. It will provide the promises value to your callbacks as usual but will not return a new promise. Thereby, saving some computation. We also take advantage of the situation and allow any uncaught errors to blow up since we know you have no plans of catching them. Furthermore, `end` will return `this` thereby allowing a jquery style use of promises which is nice where appropriate. ```javascript var p = new Promise().assign(1) .end(function(val){ // val === 1 return val + 1 }) .end(function(val){ // val === 1 return val + 1 }) .end(function(val){ // this error will not be caught throw new Error }) .then(function(val){ // val === 1 return val + 1 }, function(){ // will not handle exception since it is on another branch }) .then(function(val){ // finally val === 2 console.log(val) }) ``` I'd be surprised if that code sample conjured the picture in your head I wanted so hear is a diagram illustrating the structure of the process. ![ process ](https://docs.google.com/drawings/pub?id=1MiWhL77a7X457fWy529--ic-pKI9AG1WCmY_pZdENVg&w=960&h=720) Each box represents a process of some kind. The circles below some of the processes represent the values they expose. The first box creates the promise and exposes itself for binding. The three calls to `end` each create a process but don't create new promises. Therefore, any values they might generate are lost. The fourth call, to `then`, does the same thing as the others except it exposes a value to the outside world. This value is represented by a promise, therefore to access it we must use either `then` or `end`. In this case we used `then` which resulting in the final value being exposed. This final value is 2. The flow of data is represented by the arrows with the red boxes showing the value of the data. Hopefully this illustration makes it obvious what is happing when you access the value of a promise via `then` or `end`, you are creating a branch in the process. Values flow down these branches in the same way as errors. Though they are of course handled by separate functions. Because we chose to use `then` as the final call on the fourth branch we will be able to continue processing at any time where we left of. Be that with an error or a value, no matter, so long as the `p` variable doesn't go out of scope. In summary then we can say promises provide a mechanism to freeze process. Ready to defrost and continue via `then` and `end` as soon or as long as you like. ## Mutability Its widely considered that promises should be immutable and I agree. I though its interesting to note what happens to promises when they are implemented in a mutable way. So when a promise has its value changed it propagates this value to any child promises. At which point you would of switched to the [Reactive programming](http://en.wikipedia.org/wiki/Reactive_programming) paradigm. The change in implementation to create this effect is trivial. I guess we can say then that promises borderline bring a new paradigm to JavaScript. Its amazing how flexible this language is.

@@ -1,5 +0,7 @@

'use strict';
// 'use strict';
module.exports = Promise
function noop () {}
/**

@@ -50,4 +52,3 @@ * Promise class

var p = new Promise
// An error is a truthy value so this is safe
p.reason = p.isRejected = e
p.reason = e
p.then = rejectedThen

@@ -65,3 +66,2 @@ p.end = rejectedEnd

var p = new Promise
p.isResolved = true
p.value = value

@@ -80,10 +80,7 @@ p.then = resolvedThen

function run (fn, value) {
if (fn) {
try {
var result = fn(value)
} catch (e) {
return newRejected(e)
}
} else {
result = value
var result
try {
result = fn(value)
} catch (e) {
return newRejected(e)
}

@@ -94,3 +91,3 @@ if (isPromise(result)) {

} else {
return result instanceof Error ? newRejected(result) : newFulfilled(result)
return newFulfilled(result)
}

@@ -107,12 +104,9 @@ }

function propagate (promise, fn, value) {
if (fn) {
// Users can throw errors or return them
try {
value = fn(value)
} catch (e) {
return promise.reject(e)
}
try {
value = fn(value)
} catch (e) {
return promise.reject(e)
}
if (isPromise(value)) {
// prefer end
// prefer .end()
value[typeof value.end === 'function' ? 'end': 'then'](

@@ -123,4 +117,3 @@ function (val) {promise.resolve(val)},

else {
// Don't need to check if it's an error since `resolve` does than anyway
promise[value instanceof Error ? 'reject' : 'resolve'](value)
promise.resolve(value)
}

@@ -134,4 +127,3 @@ }

var proto = Promise.prototype
// Default states. By setting these we save some lookup time
proto.isResolved = proto.isRejected = false
// Default states.
proto.value = proto.reason = null

@@ -156,15 +148,19 @@

// The following four are used to replace the default `then` and `end` methods when the state of the promise changes
function resolvedThen (fn) {
return run(fn, this.value)
return fn
? run(fn, this.value)
: newFulfilled(this.value)
}
function rejectedThen (_, fn) {
Promise.cancelException(this)
return run(fn, this.reason)
return fn
? run(fn, this.reason)
: newRejected(this.reason)
}
function resolvedEnd (fn) {
fn && fn(this.value)
return this
}
function rejectedEnd (_, fn) {

@@ -174,6 +170,7 @@ if (!fn) throw this.reason

fn(this.reason)
return this
}
/**
* Like then but is designed for terminal operations. So any values generated will not be available for follow up and uncought errors will be thrown. Use this method in place of then when you don't plan to do anything with the stuff generated by your callbacks
* Like then but is designed for terminal operations. So any values generated will not be available for follow up and uncaught errors will be thrown. Use this method in place of then when you don't plan to do anything with the stuff generated by your callbacks
*

@@ -187,5 +184,5 @@ * @param {Function} done

this.children.push({
// Handlers are bound to the assignment properties since these aren't run inside a try catch. Since there are no handlers any values will pass straight through to the resolvers
// Handlers are bound to the assignment properties since these aren't run inside a try catch. Having no handlers is fine, the values will just pass straight through to the resolvers.
resolve: done || noop,
// Normally we don't assume reject is called with an Error instance by .end() promises are only ever called internally. Interestingly though if we didn't provide an error thrower as a backup we would still have the desired effect off throwing an error. However it would be a "no such method error" rather than the correct message which is undesirable
// Interestingly if we didn't provide an error thrower as a backup we would still be guaranteed to throw at the right time. However it would be "no such method" instead of the users error.
reject: fail || function (e) { throw e }

@@ -214,5 +211,45 @@ })

function noop () {}
/**
* If you pass callbacks it will act like .end otherwise it will attempt to return its resolution synchronously
* @param {Function} done optional
* @param {Function} fail optional
* @return {Self|Any}
*/
proto.valueOf = function (done, fail) {
if (done || fail) return this.end(done, fail)
switch (this.then) {
case resolvedThen: return this.value
case rejectedThen: return this.reason
default: return this
}
}
/**
* Convenience function for creating a propagating error handler
* @param {Function} errback
* @return {Promise}
*/
proto.otherwise = function (errback) {
return this.then(null, errback)
}
/**
* Convenience function to bind the same function to both done and fail
* @param {Function} callback
* @return {Promise}
*/
proto.always = function (callback) {
return this.then(callback, callback)
}
/**
* A terminal version version of always
* @param {Function} callback
* @return {Self}
*/
proto.finish = function (callback) {
return this.end(callback, callback)
}
/**
* Give the promise it's value and trigger all process branches

@@ -223,9 +260,7 @@ *

*/
proto.assign = proto.fulfill = proto.resolve = function (value) {
if (value instanceof Error) return this.reject(value)
proto.resolve = function (value) {
// Change the state
this.isResolved = true
this.value = value
// Change the behavior
// Change the behavior. In a parallel universe this is just a matter of swapping the prototype.
this.resolve = this.reject = noop

@@ -236,7 +271,8 @@ this.then = resolvedThen

// Propagate the value to any queued promises.
var children = this.children,
len = children.length,
i = -1
var children = this.children, child, i = 0
// Use a forward loop to maintain insertion order
while (++i < len) propagate(children[i], children[i]._success, value)
while (child = children[i++]) {
if (child._success) propagate(child, child._success, value)
else child.resolve(value)
}
return this

@@ -246,2 +282,12 @@ }

/**
* Delegates to the correct function, resolve or reject, depending on the value given
*
* @param {Any} unknown
* @return {self}
*/
proto.assign = function (unknown) {
return this[unknown instanceof Error ? 'reject' : 'resolve'](unknown)
}
/**
* Break the promise and propagate the error to subsequent process branches

@@ -253,4 +299,2 @@ *

proto.reject = function (e) {
if (!(e instanceof Error)) return this.resolve(e)
this.isRejected = true
this.reason = e

@@ -262,10 +306,11 @@

var children = this.children,
len = children.length
if (len) {
var i = 0
do propagate(children[i], children[i]._fail, e); while (++i < len)
var children = this.children, i = 0, child
if (child = children[i]) {
do {
if (child._fail) propagate(child, child._fail, e)
else child.reject(e)
} while (child = children[++i])
}
else {
// Technically a promise can never throw an error since at any time in the future a user could add a child promise and handle the exception. However in practice the promise user probably has no plans of handling rejected promise later, so in most cases unhandled rejections are genuine errors. The following method provides a place for users to access these errors.
// If a promise is rejected without any child promises we might have a genuine error. The following method provides a place for users to access these errors.
Promise.prepareException(this, e)

@@ -272,0 +317,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc