I want to implement deferred with native Promise and made some experiments.
var p, _p;
p = new Promise((t, f) => {
p.resolve = t;
p.reject = f;
_p = p; // let's save it into global
});
p.then(
console.log.bind(console, 'ok'),
console.log.bind(console, 'fail')
);
console.log(p === _p); // false!
console.log(typeof p.resolve, typeof _p.resolve); // 'undefined' 'function'
_p.resolve(42); // 'ok' 42
What p was pointed inside the promise function?
Why it is some another instance? How can I extend returned one?
What p was pointed inside the promise function?
When you're setting your p in promise, you're referencing to a global p (the one you declared).
var p, _p; // declared, but not value set
p = new Promise((t, f) => {
console.log(p); //undefined
console.log(window.hasOwnProperty("p")); //true
window.p = 3;
console.log(p); // 3
});
console.log(p); // promise
As you haven't set any value for your p before promise call, it's value is undefined.
Why it is some another instance? How can I extend returned one?
Because in the time when you're setting properties on p, your call to promise hasn't finished yet. Browser has first executes arguments you are sending to promise (that is your arrow function) , then calls your promise with arguments and only after that it assigns return value of promise to variable p (and overwrites any changes you made to p inside your arrow function).
The only way to extend the returned Promise object is to extend it after it has been created and assigned to your p
Thanks guys for point my fault.
I ended up with followed implementation:
function Deferred() {
this.promise = new Promise((ok, fail) => {
this.resolve = ok;
this.reject = fail;
});
}
!function() {
var p = new Deferred();
p.promise.then(
console.log.bind(console, 'ok'),
console.log.bind(console, 'fail')
);
p.resolve(42); // ok 42
}();
Extending of Promise object was a bad idea.
p does get reject and resolve functions appended to it when you define them:
p = new Promise((t, f) => {
console.log(p) // it is not defined as a promise
p.resolve = t;
p.reject = f;
console.log(p) // p now is defined AND has resolve and reject defined in it
_p = p // _p now is a promise object with resolve and reject defined
});
However, the moment you finish creating your promise, it will lose all the extra elements you've added to it. If you want to extend your p for whatever reason, you can do it after the promise has been created. For instance
p = new Promise((t, f) => {
console.log(p) // it is already defined as a promise
p.resolve = t;
p.reject = f;
console.log(p) // p now has resolve and reject defined in it too
_p = p // _p now is a promise object with resolve and reject defined
});
p.extraExtension = "hello"
console.log(p); // at this stage your p will have extraExtension extended to it, but its attributes and status as a Promise are also there. However, simply defining `p.resolve` and `p.reject` wouldn't make them function as proper resolve and reject methods for the promise.
Promises already have resolve and reject defined in them:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
The way to call them is to simply refer to them inside the promise object:
p = new Promise((t, f) => {
console.log(p) // it is already defined as a promise
resolve(t); // the promise will now resolve. Similarly you can call reject() here.
});
For more information refer to the official documentation here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You can see all the inherent methods and properties of a Promise object there.
Related
I was learning the event loop of Js and tried to run this function:
async function foo() {
console.log('FIrst');
let a = await new Promise((resolve,reject)=>{
console.log("inside Promise");
resolve();
})
console.log(a);
console.log('Second');
}
foo();
console.log('Three');
On running this code gave output as follows:
FIrst
inside Promise
Three
undefined
Second
I am not able to understand why did a lose its value (the object assignment). I have searched for this behavior but was not able to understand from the answers.
Can someone please explain what is the order of execution which results in this output.
When you await the newly created promise, you're not assigning the promise to a, you're assigning the resolve value of it.
async function foo() {
let a = await new Promise((resolve, reject) => {
// This is where the value stems from
resolve(42);
});
console.log(a);
}
foo();
If you want to keep the await while also retrieving the reference, you can separate those two steps:
async function foo() {
let a = new Promise((resolve, reject) => {
resolve(42);
});
await a;
console.log(a instanceof Promise);
}
foo();
This is because if you are using await it returns to a variable the thing that you've passed in resolve, so you didn't pass any value in resole this is why it is undefined
The reason why the promise's value is undefined is because you did not set the value that the promise should output. If you want the promise to return something other than undefined, place an expression or string inside the resolve() function. If you want the promise to return "Promise completed" after it resolves and console.log the result, simply use the code
async function foo() {
let a = await new Promise((resolve,reject)=>{
resolve("Promise completed");
})
console.log(a);
}
foo();
In this code block:
if I declare resolve / reject with const keyword,
I need to pass them into executor function without this, and using this will get error;
if I declare resolve / reject with this keyword,
I need to pass them into executor function with this.
What cause this different behavior?
And what differences between these two ways?
Please help me, thanks~
class myPromise {
constructor(executor) {
this.status = PENDING;
this.value = null;
this.reason = null;
const resolve = value => {
this.value = value;
}
this.reject = reason => {
this.reason = reason;
}
// Why not use this.resolve / this.reject ?
//
executor(resolve, this.reject);
}
then(onfulfilled = Function.prototype, onrejected = Function.prototype) {
onfulfilled(this.value);
onrejected(this.reason);
}
}
Why not use this.resolve / this.reject ?
this.resolve wouldn't work because resolve is not part of this. Recall that variables declared with const are only accessible in block in which they are declared, which in this case, is constructor { ... } (docs).
On the other hand, when you say this.reject you are actually assigning that value to this, and have to use this. every time you want to refer to this value again.
Something that is bugging me and my colleague. Consider the following...
const {map, compose} = require('ramda');
compose(
console.log,
map(Math.tan)
)([1,2,3]);
compose(
console.log,
map(v=>Promise.resolve(v))
)([4,5,6]);
compose(
console.log,
map(Promise.resolve)
)([7,8,9]);
As you would expect, the tan of 1, 2 and 3 are output and so are the promises resolving 3, 4 and 5. But my question is... why does the third break? Why doesn't Promise.resolve behave in the same way as any other function?
[ 1.5574077246549023, -2.185039863261519, -0.1425465430742778 ]
[ Promise { 4 }, Promise { 5 }, Promise { 6 } ]
/home/xxx/node_modules/ramda/src/internal/_map.js:6
result[idx] = fn(functor[idx]);
^
TypeError: PromiseResolve called on non-object
at resolve (<anonymous>)
at _map (/home/xxx/node_modules/ramda/src/internal/_map.js:6:19)
at map (/home/xxx/node_modules/ramda/src/map.js:57:14)
at /home/xxx/node_modules/ramda/src/internal/_dispatchable.js:39:15
at /home/xxx/node_modules/ramda/src/internal/_curry2.js:20:46
at f1 (/home/xxx/node_modules/ramda/src/internal/_curry1.js:17:17)
at /home/xxx/node_modules/ramda/src/internal/_pipe.js:3:27
at /home/xxx/node_modules/ramda/src/internal/_arity.js:5:45
at Object.<anonymous> (/home/xxx/b.js:20:6)
at Module._compile (module.js:569:30)
Promise.resolve refers to the resolve function without context object.
You want to call it with the proper context object. This can be done
by calling it on that context object, as in v => Promise.resolve(v), or
by creating a bound version of it, as in Promise.resolve.bind(Promise)
So, this would work:
compose(
console.log,
map(Promise.resolve.bind(Promise))
)([7,8,9]);
Remember that Javascript does not have classes. Functions have no owner. Objects can store functions in their properties, but that does not mean the function is owned by that object.
Another way is setting the context object explicitly, with Function#call or Function#apply:
function (v) {
var resolve = Promise.resolve;
return resolve.call(Promise, v);
}
Maybe it's best illustrated by focusing on something other than a method:
function Foo() {
this.bar = {some: "value"};
this.baz = function () { return this.bar; };
}
var f = new Foo();
var b = f.bar;
var z = f.baz;
here b refers to {some: "value"} without {some: "value"} magically "knowing" that f stores a reference to it. This should be obvious.
The same is true of z. It stores a function without that function "knowing" that f also references it. This should be just as obvious, in theory.
Calling z() will yield different results than calling f.baz(), even though the called function is the same one. Only the context is different.
When a function is called its this variable is dynamically allocated a value.
The resolve function cares what that value is.
The third part of your code passes the resolve function and then calls it without the context of the Promise object.
This means that this does not get allocated the value of Promise which the function needs.
Promise.resolve needs to be called with this being a Promise constructor (or subclass).
resolve = Promise.resolve;
resolve(null); // Error
resolve.call({}); // Error: Object is not a constructor
So change this line:
map(Promise.resolve)
to:
map(Promise.resolve.bind(Promise))
I'm trying to chain Q promises without 'then', so eventually the chain would look like this:
var foo = new Foo();
foo
.method1()
.method2()
.method3();
How to implement foo's methods so each one is executed once the promise of the previous one is resolved?
This question was marked as exact duplicate of this one but I'm trying to implement this using Q lib, not jQuery.
I'm not sure if you are going to gain anything with this.
I suppose that you can do something like this:
function Foo() {
var self = this,
lastPromise = Promise.resolve();
var chainPromise = function(method) {
return function() {
var args = Array.prototype.slice.call(arguments))
lastPromise = lastPromise.then(function(){
return method.apply(self, args);
});
return self;
}
}
this.method1 = chainPromise(function() {
// do the method1 stuff
// return promise
});
this.method2 = chainPromise(function() {
// do the method2 stuff
// return promise
});
// etc...
}
This question already has answers here:
Object method with ES6 / Bluebird promises
(2 answers)
Closed 7 years ago.
Simple example of my problem
Consider the following situation, where I have a few functions (a and b) that I used in a promise-chain in c:
class SomeClass {
constructor(){
this.v1 = 1;
this.v2 = 2;
}
a() {
return new Promise((resolve, reject) => {
console.log('a', this.v1); // Do something with `this`
resolve();
});
}
b() {
return new Promise((resolve, reject) => {
console.log('b', this.v2); // Do something with `this`
resolve();
});
}
c() {
return this.a().then(this.b); // passing b as argument
}
}
When I call c and run the chain of promises, this is undefined in b.
const sc = new SomeClass();
sc.c().then(() =>{
console.log('done')
}).catch((error) => {
console.log('error', error);
});
Output:
a 1
error [TypeError: Cannot read property 'v2' of undefined]
I know that arrow functions inherit the outer this, but I am not sure why it is undefined since I am invoking it from c.
The problem is here:
this.a().then(this.b)
because the resulting function retrieved by this.b becomes unbound from this (you don't actually invoke it in the way stated in your question).
You can solve it in a way that is consistent with the rest of your code, by using an arrow method to preserve scope:
this.a().then(obj => this.b(obj))
or you can use .bind to achieve a similar result:
this.a().then(this.b.bind(this))