How to pass arguments for bluebird callback in then()? - javascript

I have a call that returns promise. At this moment, I do this:
Something( ... )
.then(()=>{console.log("Done.");});
This would be more practical:
Something( ... )
.then(console.log, "Done.");
For example, setTimeout works like that:
setTimeout(console.log, 1000, "Done.");
Does Bluebird have any method for this? My aim is to have this practical option to reduce the already ridiculous amount of code that Promises generate.

At this moment, I do this:
Something(…).then(()=>{console.log("Done.");});
This is the correct approach. Arrow functions already shorten this a lot. Notice that you can drop the "{"…";}" parts.
This would be more practical:
Something(…).then(console.log, "Done.");
No it would not. The second parameter of then is the onRejected callback, not a string. You can't do that.
My aim is to reduce the already ridiculous amount of code that
Promises generate.
Then use async/await syntax and a transpiler. It's as simple as
await Something(…);
console.log("Done");
Does Bluebird have any method for this?
If you don't like to use a transpiler but are in an ES6 environment (like a recent Node.js), you can use generator functions to imitate async/await with Promise.coroutine.

That feature is pretty much exclusive to setTimeout. IE9 and below requires a polyfill for that anyway https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
The following would is a workaround for your example case using console.log. Be cautious using it with any function that references this. You can use bind to set the value of this or leave it undefined. Also, it will log the resolved value of the promise after "Done" due to the value being automatically passed as the last argument to bind.
Something( ... )
.then(console.log.bind(undefined, "Done."));

#Bergi gave an excellent answer to your question. Just to add, if you use () => console.log("Done.") or some other general callback a lot, make it a separate function:
function afterSomething() {
console.log("Done.");
}
Something( ... )
.then(afterSomething);

Related

Testing Promise.all

I have an async function that looks something like this:
const myMethod = async () => {
await Promise.all(
someIds.map((id) => {
someMethodThatReturnsPromise(id);
});
);
doSomethingElseAfterPromisesResolve();
};
This function contains a bug because it uses curly braces in its map function but doesn't return each promise. The Promise.all consumes the undefined return value and silently proceeds to the next statement, without waiting. The problem can be corrected by using parentheses instead of braces, or by including an explicit return statement.
My question is, how can I test this? I know I can use Promise.resolve() or Promise.reject() to simulate different states of the promise, and mock the return values of the inner method, but that doesn't really cover the problem. Outside a full blown integration test, how can I prevent the above error with a test?
Well, the issue is not that Promise.all() accepts null, it doesnt. What it accepts is arrays of the kind of [null] or [undefined] (which are 2 different things, actually)
As I mentioned in my comments, testing Promise.all() is not something I would do, it's third party code, you should be testing your own, so I think having a linter check for such bugs is a far superior solution
That being said, you are entitled to your opinions, I'll merely point out a possibility for achieving what you want. That is: monkey patching
You could overwrite the Promise.all() like so:
let originalAll = Promise.all;
Promise.all = (promises) => {
// you could check several other things
// but this covers what you wanted, right?
let isArrayWithBlanks = promises.includes(null) || promises.includes(undefined);
return isArrayWithBlanks
? Promise.reject("NO!")
: originalAll(promises);
};
Now you can easily write a test given you use this monkey patched Promise.all throughout your project. You decide where to place that code
Hope this helps
I would stub both the someMethodThatReturnsPromise and doSomethingElseAfterPromisesResolve functions, returning any value from both.
Then ensure that someIds has multiple values.
Your assertions could then be:
someMethodThatReturnsPromise is called once for each item in the someIds array
doSomethingElseAfterPromisesResolve is called

AngularJS Why use $q.all() on one promise?

I'm familiarizing myself with a codebase, and I'm seeing this everywhere:
$q.all([promise]).then(responseFunc);
This does not make sense to me -- I've read the documentation, and I don't know why the following is not used instead, since it's already one promise...
promise.then(responseFunc);
Is there something I'm missing? What's the advantage of the former over the latter?
Yes, this is a bit weird, but there is a difference: responseFunc will be called with an array of the result instead of the result itself.
This probably should better be written as either
promise.then(res => responseFunc([res]))
or
promise.then(Array.of).then(responseFunc)
Ok, here's the only advantage I can think of (based on my comment above)
function responseFunc(arr) {
arr.forEach(data => {
// do stuff with data
});
}
$q.all([promise1, promise2]).then(responseFunc);
$q.all([promise]).then(responseFunc);

What does "Non-constructor value passed to NewPromiseCapability" mean?

I used Kris Kowal's Q, but now I'm trying to lighten the number of libraries, so I'm switching to native Promises (but yes, I'm using a polyfill to support internet explorer).
Most of my functions return promises, but there was a place where I wanted to expose Q.all as being supplied by my own code. When I did:
MyLibrary.prototype.all = Promise.all;
..., and used it (myLibrary.all([...]).then(...)), I got "Non-constructor value passed to NewPromiseCapability." What does that mean?
MyLibrary never properly inherited from Promise, so the context ("this") was lost.
To fix, instead of doing myLibrary.all([...]), I'm just using Promise.all([...]).
I suppose another option could have been to bind .all() to Promise by MyLibrary.prototype.all = Promise.all.bind(Promise)

Is there a way to sequentially execute statements in Javascript?

A number of times, I have to write a callback function.
Example 1:
myTransaction.executeSql(stmt,parameters,mySuccess,myError);
Example 2: $.getScript(url [, mySuccess])
Q: Is there a way to tell JavaScript, "Please execute this line of code, and when you're done, execute the next line of code"?
I don't want to lock up the browser session, I just want it to not run the next line until it's done.
Put the call to the second function in the mySuccess handler function for the first function call. When the first one completes and runs the mySuccess function, that function will then call the second one. That is the design pattern for sequencing asynchronous operations.
You cannot write normal sequential function calls with asynchronous operations. You must use the completion functions to do your sequencing.
Here's an example using an anonymous success handler for the first function:
myTransaction.executeSql(stmt,parameters,function() {
$.getScript(url, mySuccess);
}, myError);
No there is not a way to exactly what you want. But you can use a library that helps make this less hard, like Step: https://github.com/creationix/step
Step(
function() { myTransaction.executeSql(stmt, parameters, this, myError) },
function() { $.getScript(url, this); },
function() { alert('done'); }
);
Or you will need to manually nest the callbacks.
The Javascript library Step provides a framework that encapsulates the solution suggested by #jfriend00.
You can put step 2's call in step 1's success/complete callback, as already mentioned.
Or you can look into the promise/deferred paradigm. It's a little complicated, so I won't try and explain it concisely here (and get it wrong). But given that you already seem to be using jQuery you can probably use its implementation of the deferred object. Here are a couple of articles you can read (though there are plenty more that you'll find with Google):
http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx
http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/
http://www.infoq.com/articles/surviving-asynchronous-programming-in-javascript
Frame.js is another library, similar to Step, that solves this problem eloquently and provides a host of advantages over setTimeouts or nested callbacks.

wait for async javascript function to return

I am using a function supplied by a third party library. This function takes a callback function as a parameter, but I would like to wait for this callback to be called before continuing. Is there a standard / accepted way to do this?
I am not sure if this is a possible solution for you but you can achieve the desired result by breaking your code into 2 functions.
Suppose this is what you intend to do:
Basically this is your original function:
function origFunc() {
codeBeforeThirdPartyFunc();
ThirdPartyFunc(oldCallBackFunc);
Wait();
codeAfterCallBackFunc();
}
You can modify the code flow with something like:
function newFunc() {
codeBeforeThirdPartyFunc();
ThirdPartyFunc(newCallBackFunc);
}
function newCallBackFunc() {
oldCallBackFunc();
codeAfterCallBackFunc();
}
This will eliminate the wait loop. And as far as I know, busy waiting doesn't work in IE (because ? God only knows)..
Here's another method of loading jQuery asynchronously, which doesn't depend on another script.
I don't know if Sharad's solution would work in all cases (for instance if you function calls are so far chained that you have to pass data as variables instead of parameters). Same problem with global variables. JavaScript just doesn't have a "wait" ability.
Although I had a similar problem and with jQuery, I ended up with a MacGyver type solution that gives you tons of control on when javascript functions execute. I just posted it here as an answer to my own question (but I it's an answer that's not checked - look for my username Emile): How to get a variable returned across multiple functions - Javascript/jQuery

Categories