Is It Safe To Resolve A Promise Multiple Times?
Solution 1:
As I understand promises at present, this should be 100% fine. The only thing to understand is that once resolved (or rejected), that is it for a defered object - it is done.
If you call then(...)
on its promise again, you immediately get the (first) resolved/rejected result.
Additional calls to resolve()
will not have any effect.
Below is an executable snippet that covers those use cases:
var p = newPromise((resolve, reject) => {
resolve(1);
reject(2);
resolve(3);
});
p.then(x =>console.log('resolved to ' + x))
.catch(x =>console.log('never called ' + x));
p.then(x =>console.log('one more ' + x));
p.then(x =>console.log('two more ' + x));
p.then(x =>console.log('three more ' + x));
Solution 2:
I faced the same thing a while ago, indeed a promise can be only resolved once, another tries will do nothing (no error, no warning, no then
invocation).
I decided to work it around like this:
getUsers(users => showThem(users));
getUsers(callback){
callback(getCachedUsers())
api.getUsers().then(users => callback(users))
}
just pass your function as a callback and invoke it as many times you wish! Hope that makes sense.
Solution 3:
There s no clear way to resolve promises multiple times because since it's resolved it's done. The better approach here is to use observer-observable pattern for example i wrote following code that observes socket client event. You can extend this code to met your need
constevokeObjectMethodWithArgs = (methodName, args) => (src) => src[methodName].apply(null, args);
consthasMethodName = (name) => (target = {}) =>typeof target[name] === 'function';
constObservable = function (fn) {
const subscribers = [];
this.subscribe = subscribers.push.bind(subscribers);
const observer = {
next: (...args) => subscribers.filter(hasMethodName('next')).forEach(evokeObjectMethodWithArgs('next', args))
};
setTimeout(() => {
try {
fn(observer);
} catch (e) {
subscribers.filter(hasMethodName('error')).forEach(evokeObjectMethodWithArgs('error', e));
}
});
};
constfromEvent = (target, eventName) => newObservable((obs) => target.on(eventName, obs.next));
fromEvent(client, 'document:save').subscribe({
asyncnext(document, docName) {
awaitwriteFilePromise(resolve(dataDir, `${docName}`), document);
client.emit('document:save', document);
}
});
Solution 4:
If you need to change the return value of promise, simply return new value in then
and chain next then
/catch
on it
var p1 = newPromise((resolve, reject) => { resolve(1) });
var p2 = p1.then(v => {
console.log("First then, value is", v);
return2;
});
p2.then(v => {
console.log("Second then, value is", v);
});
Solution 5:
You can write tests to confirm the behavior.
By running the following test you can conclude that
The resolve()/reject() call never throw error.
Once settled (rejected), the resolved value (rejected error) will be preserved regardless of following resolve() or reject() calls.
You can also check my blog post for details.
/* eslint-disable prefer-promise-reject-errors */const flipPromise = require('flip-promise').defaultdescribe('promise', () => {
test('error catch with resolve', () =>newPromise(async (rs, rj) => {
constgetPromise = () => newPromise(resolve => {
try {
resolve()
} catch (err) {
rj('error caught in unexpected location')
}
})
try {
awaitgetPromise()
thrownewError('error thrown out side')
} catch (e) {
rs('error caught in expected location')
}
}))
test('error catch with reject', () =>newPromise(async (rs, rj) => {
constgetPromise = () => newPromise((_resolve, reject) => {
try {
reject()
} catch (err) {
rj('error caught in unexpected location')
}
})
try {
awaitgetPromise()
} catch (e) {
try {
thrownewError('error thrown out side')
} catch (e){
rs('error caught in expected location')
}
}
}))
test('await multiple times resolved promise', async () => {
const pr = Promise.resolve(1)
expect(await pr).toBe(1)
expect(await pr).toBe(1)
})
test('await multiple times rejected promise', async () => {
const pr = Promise.reject(1)
expect(awaitflipPromise(pr)).toBe(1)
expect(awaitflipPromise(pr)).toBe(1)
})
test('resolve multiple times', async () => {
const pr = newPromise(resolve => {
resolve(1)
resolve(2)
resolve(3)
})
expect(await pr).toBe(1)
})
test('resolve then reject', async () => {
const pr = newPromise((resolve, reject) => {
resolve(1)
resolve(2)
resolve(3)
reject(4)
})
expect(await pr).toBe(1)
})
test('reject multiple times', async () => {
const pr = newPromise((_resolve, reject) => {
reject(1)
reject(2)
reject(3)
})
expect(awaitflipPromise(pr)).toBe(1)
})
test('reject then resolve', async () => {
const pr = newPromise((resolve, reject) => {
reject(1)
reject(2)
reject(3)
resolve(4)
})
expect(awaitflipPromise(pr)).toBe(1)
})
test('constructor is not async', async () => {
let val
let val1
const pr = newPromise(resolve => {
val = 1setTimeout(() => {
resolve()
val1 = 2
})
})
expect(val).toBe(1)
expect(val1).toBeUndefined()
await pr
expect(val).toBe(1)
expect(val1).toBe(2)
})
})
Post a Comment for "Is It Safe To Resolve A Promise Multiple Times?"