I have this ES6 code in Puppeteer:
async function waitForSelectorReversed(page, selector) {
await page.waitFor(() => !document.querySelector(selector));
}
When I call this code I get the error Evaluation failed: ReferenceError: selector is not defined. I understand that this error is caused by the fact that the code inside the closure can't access the variable from the outer scope. What is a way of getting this to work?
You need to explicitly pass outer scope variables into into page.waitFor for it to work. As the documentation states:
To pass arguments from node.js to the predicate of page.waitFor function:
const selector = '.foo';
await page.waitFor(selector => !document.querySelector(selector), {}, selector);
For your code, all you need to do is remove the first line, since selector is already defined.
This isn't so much a plain Javascript thing or an ES6 thing, it's a quirk of how Puppeteer (and Puppeteer-like tools) work when interacting with the page.
Related
I'm quite new to Kotlin. I hit this part while I was going over the docs:
"a lambda cannot return from the enclosing function" (unless it's inlined).
So, this doesn't work;
fun foo() {
ordinaryFunction {
return // ERROR: cannot make `foo` return here
}
}
I wonder why it works that way?
The only thing I can think of it's dangerous since there might be some extra stuff the enclosing function might be doing after the lambda execution. But I'm not sure that's the reason because you can overcome this by using qualified returns or using inline keyword. So, that kind of implies there's a technical reason behind it (apart from any usability/safety reasons) like the compiler cannot figure out where to return unless it's labeled or inlined.
Any help would be great!
The problem is here that non-local returns can't be done on the JVM.
If you want to return from lambda (local return) you can add label #ordinaryFunction:
fun foo() {
ordinaryFunction {
return#ordinaryFunction
}
}
Docs say:
If we need to return from a lambda expression, we have to label it and qualify the return. Oftentimes it is more convenient to use implicit labels: such a label has the same name as the function to which the lambda is passed. In our case it is #ordinaryFunction.
Someone else can probably explain this better but in pretty much any programming language, when you call a function, a new entry is created on top of the stack. The stack keeps information about the arguments that the function was called with and the place you should return to when the function completes.
Kotlin doesn't have a feature that lets you return from multiple function calls in one return, so you have to return from each function call manually.
When you inline a function the machine code that would normally execute in a separate subroutine is now copy pasted to the function call site instead. That's why return from an inline function actually returns from the function that called the inlined lambda.
there might be some extra stuff the enclosing function might be doing after the lambda execution.
The problem is the other way around: the lambda can "escape" from the enclosing function's scope and end up executing after the function returns. E.g. consider
fun foo() {
Thread(Runnable {
Thread.sleep(1000)
return
})
}
Or just
fun foo() = // lambda
In either case it makes no sense for the lambda to return from foo, does it? And the compiler doesn't know if your ordinaryFunction lets the lambda escape foo's scope unless it's inline.
you can overcome this by using qualified returns
That's not really overcoming, that's just not returning from the enclosing function.
My question is: Is it okay to pass a promise to the first argument of .then? (Assuming that I'm not interested in the returned value of the previous promise and I just want to chain promises together).
Someone told me that if I do this, a new promise will be created
implicitly (unnecessarily), and I might face issues handling errors
bellow in the promise chain.
I know that if you don't explicitly return a promise in an async method the result will be implicitly wrapped. In this case, .then should not wrap the argument in a promise since the argument is already a promise :/
Example:
async function asyncFunc() {
//async function (return Promise)
}
// I know this is okay
somePromise.then(() => asyncFunc());
// BUT... is this okay?
somePromise.then(asyncFunc());
Is it okay to pass a promise to the first argument of .then?
Yes.
Someone told me that if I do this, a new promise will be created implicitly (unnecessarily)
Promise.prototype.then() returns a new promise either way.
// BUT... is this okay?
somePromise.then(asyncFunc());
No, it is more or less the same as:
const p = asyncFunc()
somePromise.then(p);
You execute the function before somePromise actually resolves. What you probably want instead is somePromise.then(asyncFunction). This will properly chain the promises after each other.
Someone told me that [...] I might face issues handling errors bellow in the promise chain.
No. This does not change the behaviour of the promise chain as long as long as there is a catch at the end of the chain.
I'm using babel's require hook in node to leverage ES6 but I'm running into some challenges with arrow functions in bluebird promise chains.
I use .bind({}) at the top of my promise chain with an empty object to create shared state where I can store previous values until I need them further down the chain. Bluebird explains this usage as a "useful side purpose".
When I switch to arrow functions, I can no longer use shared state because arrow functions use lexical this which is undefined in babel (babel automatically runs in strict mode).
Working example: https://jsbin.com/veboco/edit?html,js,console
ES6 example (not working): https://jsbin.com/menivu/edit?html,js,console
Is there any way to take advantage of arrow functions in this situation? In my code I call these methods from within an object method - shouldn't this be defined as the object from which the method is called?
If you don't want lexically bound this, there's no need to use arrow functions. If you want dynamically bound this, just don't use arrow functions.
Of course, you could scrap that .bind({}) as a whole and use arrow functions that are bound to the object by putting everything in an object method (or an IIFE in your example):
(function() {
this; // the value that everything is bound to
double(2).then(result => {
this.double = result; // store result here
return triple(2);
}).then(result => {
console.log('double:', this.double);
console.log('triple:', result);
console.log('sum:', this.double + result);
}).catch(err => {
console.log(err.message);
});
}.call({}));
However, there are much better ways to access previous results in a promise chain than contextual state, especially if you are using ES6!
I was testing Jakobs patch on the Sortables Class and this line this.reset() gave me a Uncaught TypeError: undefined is not a function.
I don't understand why since the Class has a method reset.
So my solution was to a var self = this; inside the same end: method (here), and called self.reset(); in the same line as I had this.reset(); before. Worked good. Why?
Then just to check (I suspected already) I did a console.log(this == self) and gave false.
Why does using self work but not this?
Fiddle
In javascript the this keyword change accordingly with the execution context
in global code this refer to the global object
inside eval the scope is the same as the calling context one, if no context provided then is the same as above
in all the case below if the this argument passed to .bind .call or .apply is not an object (or null) this will be the global object
when using a function which has been binded to a specific object using .bind then this refers to the this argument passed to bind, the function is now permabinded.
when running a function the context is provided from the caller, if before the function call operator () there is a dot(.) or a [] operator then this refers to the part on the left of such operator, unless the function is permabinded to something else or we are using .call or .apply if so this refers to the this argument unless the function was previously permabinded;
if before the function call operator () there neither the . nor the [] operators then this will refer to the global object (unless the function stores the result of the .bind function)
when running a constructor function (basically when using new) this refers to the object we are creating
now when using the use strict directive things changes a bit, mostly instead of the global object when the context is not given this will be null, but not in all the cases.
I rarely use "use strict" so I just suggest to try it by yourself when in need.
now, what happens when a function is cached inside a variable like this:
var cache = 'A.foo'
if that you lose the context in which the original function was stored, so in this case foo will not be anymore a property on the instance A and when you run it using
cache()
the context will be evaluated using the rules I wrote above in this case the this will refer to the global object.
The semantics of "this" in Javascript are not what is expected by OO programmers. The symbol "this" refers to the dynamic/runtime calling context, not the lexicographic context. For example, if you have an object A with "method" and then do B.method = A.method; B.method(); then the context is now B and that is what this will point to. The difference becomes very apparent in "handler" type situations where the calling context is usually the object with the handler installed.
Your solution using self is sound.
kentaromiura's answer is absolutely right.
That said, mootools provides function.bind() as a way to decide what this will refer inside of your function. this means that if you simply do this :
var destroy = function () {
`bind() [...]
this.reset();
}.bind(this);
it will work as you intended (that is, this will be the same inside of destroy() and outside).
Now, a lot of coders will balk at fiddling with the context, with good reason as it is very difficult to read and maintain. But here you have it and I think bind() is a very nifty trick of mootools.
I'm writing a simple Twitter client to play with coffeescript. I have an object literal with some functions that call each other via callbacks.
somebject =
foo: 'bar'
authenticateAndGetTweets: ->
console.log "Authorizing using oauth"
oauth = ChromeExOAuth.initBackgroundPage(this.oauthdetails)
oauth.authorize( this.afterLogin.call this )
afterLogin: ->
this.getTweets(this.pollinterval)
This code works perfectly. Edit: actually this.afterlogin should be sent as a callback above, not ran immediately, as Trevor noted below.
If, within authenticateAndGetTweets, I removed the 'call' and just ran:
oauth.authorize( this.afterLogin )
and don't use 'call', I get the following error:
Uncaught TypeError: Object [object DOMWindow] has no method 'getTweets
Which makes sense, since 'this' in afterLogin is bound to the thing that initiated the callback rather than 'someobject' my object literal.
I was wondering if there's some magic in Coffeescript I could be doing instead of 'call'. Initially I thought using the '=>' but the code will give the same error as above if '=>' is used.
So is there a way I can avoid using call? Or does coffeescript not obviate the need for it? What made '=>' not work how I expected it to?
Thanks. I'm really enjoying coffeescript so far and want to make sure I'm doing things 'the right way'.
As matyr points out in his comments, the line
oauth.authorize( this.afterLogin.call this )
doesn't cause this.afterLogin to be called as a callback by oauth.authorize; instead, it's equivalent to
oauth.authorize this.afterLogin()
Assuming that you want this.afterLogin to used as a callback by oauth.authorize, megakorre's answer gives a correct CoffeeScript idiom. An alternative approach supported by many modern JS environments, as matyr points out, would be to write
oauth.authorize( this.afterLogin.bind this )
There's no CoffeeScript shorthand for this, partly because Function::bind isn't supported by all major browsers. You could also use the bind function from a library like Underscore.js:
oauth.authorize( _.bind this.afterLogin, this )
Finally, if you were to define someobject as a class instead, you could use => to define afterLogin such that it's always bound to the instance, e.g.
class SomeClass
foo: 'bar'
authenticateAndGetTweets: ->
console.log "Authorizing using oauth"
oauth = ChromeExOAuth.initBackgroundPage(this.oauthdetails)
oauth.authorize(this.afterLogin)
afterLogin: =>
this.getTweets(this.pollinterval)
someobject = new SomeClass
you can put a lambda in the function call like so
auth.authorize(=> #afterLogin())
You have to use either the call or apply methods because they set the scope of the function (the value of this). The error results because the default scope is the window object.