6 ms·
I've just been playing with Promises and like them a lot. But one thing I find strange is that ".then()" creates a new promise, but with no way to reject it.
by haberman 11y ago
I've just been playing with Promises and like them a lot. But one thing I find strange is that ".then()" creates a new promise, but with no way to reject it.
ie. I can't write:
return new Promise((resolve, reject) => {
// Do some stuff, call resolve()/reject() on success/failure.
}).then((step1Val, resolve, reject) => {
// Do some stuff, call resolve()/reject() on success/failure.
// But this doesn't actually work, because the "then" callback
// doesn't get resolve/reject as args.
});
Instead I'm having to write this as the following, which is more verbose:
return new Promise((resolve, reject) => {
// Do some stuff, call resolve()/reject() on success/failure.
}).then(new Promise((resolve, reject) = {
// Do some stuff, call resolve()/reject() on success/failure.
// But this way I don't get access to step1Val.
}));
Another bummer of this style is that that the second step doesn't get access to the first step's value.
- 15155 11y agoasync/await solves error handling and hanging onto values quite nicely. IMO you should use Babel and take advantage.
- haberman 11y agoI am using Babel already. Not sure I'm ready to dip into ES7 features though. ES6 feels bleeding-edge enough for me.
- grandalf 11y agolink to example please
- 15155 11y agoasync function foo() { try { const valueOne = await promiseReturningFunction(); const valueTwo = await anotherAsyncFunction(valueOne); return valueTwo; } catch (err) { alert(err); } } foo(); //Returns a Promise. ---- In this example, I've sequenced the resolution of two promises (async functions return Promises when invoked) If either of these Promises reject or throw an error, or if any of the code within the try {} block throws an error, the error will be caught inline in the catch block (one area only). You can also see that both Promise's return values are in-scope and continually usable (vs. losing scope with 'then' chains).
- grandalf 11y agoI see. Not sure what the best practice is for the losing scope in then chains issue with promises. I ended up creating something along the lines of a message object designed for each chain, which felt like a smell.
- 15155 11y agoFeels like an un-compiler-assisted State monad. IMO threading an object through is probably the best method, unfortunately. You could use an Immutable Record or something to help keep it under control. I would personally just use async/await to more explicitly handle the sequencing/binding.
- grandalf 11y agoAgreed. I think I'll refactor... thanks for the example.
- regecks 11y agoThrow an Error to reject it.
- AgentME 11y agoThere is a way to reject it in the .then() callback. You just throw.
- haberman 11y agoSo in the first function you call reject, but in the second function you throw? I don't love the asymmetry. Also how do you return a value from the second callback? Just return? If throw and return work that way for then() functions, why not the same for the initial function?
- jkrems 11y agoBecause the initial one is where you'd interface (potentially) with non-promise code. E.g. in order to wrap a node-style function, you can't throw or return. But in general you shouldn't need to use `new Promise()`, that should in most cases be reserved to more general, low-level code (e.g. a promisify implementation).
- haberman 11y agoI'm writing code against indexedDB (which doesn't use promises), but I want to expose promises to my callers. So I'm wrapping my indexedDB usage in Promises. Also some of indexedDB doesn't seem like it would fit with promises, since some operations have 3 or more callbacks (onsuccess, onerror, onupgradeneeded).
- jbergens 11y agoThere are a number of IndexedDb libraries that uses promises. However, there is or was a problem with how IndexedDb is specified to work that is not really compatible with promises. I'm not sure if they have fixed this yet. https://github.com/promises-aplus/promises-spec/issues/45#issuecomment-10486869 https://github.com/promises-aplus/promises-spec/issues/45#is...
- haberman 11y ago
- deleted 11y ago[deleted]
- haberman 11y ago> .then() does not create a new promise The docs for Promise say that then() returns a promise. Are you saying it returns the original promise (ie. this)? > But if your call to then isn't a Promise or a function that returns a Promise, your chain ends. I don't think this is correct. The docs show examples of chains of then() calls where the intermediate function isn't returning a promise. See "chaining": https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- cjbprime 11y ago> .then() does not create a new Promise It returns a promise, right? > var foo = Promise.resolve([1,2,3]).then(function() { return 5 }) > foo < Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 5}
- chncdcksn 11y ago.then() does create a new promise. Return Promise.reject() in the fulfillment function to reject the new promise. somethingThatReturnsPromiseWithoutError() .then((res) => { return Promise.reject("some error"); }) .catch((err) => { console.log(err); // => some error }); Promise.resolve() and Promise.reject() return a promise resolved or rejected to the value passed in the first argument. Returning a promise in the fulfillment function passed to .then() chains the promises together. somethingThatReturnsPromise() .then((foo) => { return foo.bar; // Or if you like it more verbose return Promise.resolve(foo.bar); // Or pass bar to a function modifying bar that returns a promise return modifyBarReturnPromise(foo.bar); }) .then((newBar) => { console.log(newBar); }); In your case, if you need step1Val in next promise chain, I personally do this, however people more familiar with promises may know of a better way to do it (maybe with something like Promise.all() or Promise.props() in the BlueBird library). somethingThatReturnsPromise() .then((first) => { doSomethingWithFirstAndReturnPromise(first) .then((second) => { console.log(first + second); }); });
- mikekchar 11y agoIt took me a while to understand this correct response because I couldn't understand the documentation for promises. For the benefit of any other person who was likewise confused... then() returns a new promise resolved to the return value of the function. However, if that value is itself a promise, then it follows the promise chain and passes the eventual state to the next then()/catch() call.
- seniorsassycat 11y agoI like Jquery's Deferred better then ES6 Promise. Promises lack the `always` callback, they don't have any `progress` events. The spec on mdn[0] doesn't mention asynchronous `then` or `catch` behavior. If the callback in Jquery `Deferred#then` returns a Deferred that deferred will be returned by `then`. // Basic async function, resolves after n milliseconds function wait(n) { var promise = $.Deferred(); setTimeout(promise.resolve, n); return promise; } wait(10) .then(function() { console.log('first'); // prints first after 10 milliseconds return wait(10); }) .then(function() { console.log('second'); // prints second after 20 milliseconds return 'done'; }) You can 'flip' a failed promise by returning a resolve promise in the fail callback. var promise = $.Deferred(); setTimeout(promise.reject, 100) promise.then(null, function () { return $.Deferred().resolve([]); }).done(function(arg) { console.log(arg); // Prints '[]' }) [0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- tracker1 11y agoI don't see the problem... function doSomething() { return new Promise((resolve,reject)={ setTimeout(reject,100); }) .catch(() => []) } doSomething().then((arg) => console.log(arg));
- seniorsassycat 11y agoThe problem may have just been the docs. They say .catch and .then can be composed but I didn't see any mention of the behavior.
- inglor 11y agoYou can reject inside a `then` by `throw`ing an error, like synchronous try-catch.
- spion 11y agoYou don't need resolve or reject. Just return the promise: .then(val => doSomeStuff()) Thats it. The resulting promise will get resolved/rejected based on the return result of doSomeStuff() You can also use throw to reject a promise manually, or return Promise.reject() .then(val => { if (something) return successVal; else throw new Error("Failure"); }); For more complex scenarios where I need the values from previous actions, I like the forgoing the chaining and using a join helper to unwrap any set of promises as needed: let url = getUrl(resource); let data = url.then(url => fetch(url)) let updateData = d => _.assign(d, {field: 'newVal'} let update = join(url, data, (url, data) => sendUpdate(url, updateData(data))