I have been using ES6 Promise.
Ordinarily, a Promise is constructed and used like this
new Promise(function(resolve, reject){
if (someCondition){
resolve();
} else {
reject();
}
});
But I have been doing something like below to take the resolve outside for the sake of flexibility.
var outsideResolve;
var outsideReject;
new Promise(function(resolve, reject) {
outsideResolve = resolve;
outsideReject = reject;
});
And later
onClick = function(){
outsideResolve();
}
This works fine, but is there an easier way to do this? If not, is this a good practice?
simple:
var promiseResolve, promiseReject;
var promise = new Promise(function(resolve, reject){
promiseResolve = resolve;
promiseReject = reject;
});
promiseResolve();
Bit late to the party here, but another way to do it would be to use a Deferred object. You essentially have the same amount of boilerplate, but it's handy if you want to pass them around and possibly resolve outside of their definition.
Naive Implementation:
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject)=> {
this.reject = reject
this.resolve = resolve
})
}
}
function asyncAction() {
var dfd = new Deferred()
setTimeout(()=> {
dfd.resolve(42)
}, 500)
return dfd.promise
}
asyncAction().then(result => {
console.log(result) // 42
})
ES5 Version:
function Deferred() {
var self = this;
this.promise = new Promise(function(resolve, reject) {
self.reject = reject
self.resolve = resolve
})
}
function asyncAction() {
var dfd = new Deferred()
setTimeout(function() {
dfd.resolve(42)
}, 500)
return dfd.promise
}
asyncAction().then(function(result) {
console.log(result) // 42
})
No, there is no other way to do this - the only thing I can say is that this use case isn't very common. Like Felix said in the comment - what you do will consistently work.
It's worth mentioning that the reason the promise constructor behaves this way is throw safety - if an exception you did not anticipate happens while your code is running inside the promise constructor it will turn into a rejection, this form of throw safety - converting thrown errors to rejections is important and helps maintain predictable code.
For this throw safety reason, the promise constructor was chosen over deferreds (which are an alternative promise construction way that do allow what you're doing) - as for best practices - I'd pass the element and use the promise constructor instead:
var p = new Promise(function(resolve, reject){
this.onclick = resolve;
}.bind(this));
For this reason - whenever you can use the promise constructor over exporting the functions - I recommend you do use it. Whenever you can avoid both - avoid both and chain.
Note, that you should never use the promise constructor for things like if(condition), the first example could be written as:
var p = Promise[(someCondition)?"resolve":"reject"]();
I liked #JonJaques answer but I wanted to take it a step further.
If you bind then and catch then the Deferred object, then it fully implements the Promise API and you can treat it as promise and await it and such.
⚠️ Editor's Note: I don't recommend this kind of pattern anymore since at the time of writing, Promise.prototype.finally was not a thing yet, then it became a thing… This could happen to other methods so I recommend you augment the promise instance with resolve and reject functions instead:
function createDeferredPromise() {
let resolve
let reject
const promise = new Promise((thisResolve, thisReject) => {
resolve = thisResolve
reject = thisReject
})
return Object.assign(promise, {resolve, reject})
}
Go upvote someone else's answer.
class DeferredPromise {
constructor() {
this._promise = new Promise((resolve, reject) => {
// assign the resolve and reject functions to `this`
// making them usable on the class instance
this.resolve = resolve;
this.reject = reject;
});
// bind `then` and `catch` to implement the same interface as Promise
this.then = this._promise.then.bind(this._promise);
this.catch = this._promise.catch.bind(this._promise);
this.finally = this._promise.finally.bind(this._promise);
this[Symbol.toStringTag] = 'Promise';
}
}
const deferred = new DeferredPromise();
console.log('waiting 2 seconds...');
setTimeout(() => {
deferred.resolve('whoa!');
}, 2000);
async function someAsyncFunction() {
const value = await deferred;
console.log(value);
}
someAsyncFunction();
A solution I came up with in 2015 for my framework. I called this type of promises Task
function createPromise(handler){
var resolve, reject;
var promise = new Promise(function(_resolve, _reject){
resolve = _resolve;
reject = _reject;
if(handler) handler(resolve, reject);
})
promise.resolve = resolve;
promise.reject = reject;
return promise;
}
// create
var promise = createPromise()
promise.then(function(data){ alert(data) })
// resolve from outside
promise.resolve(200)
Accepted answer is wrong. It's pretty easy using scope and references, though it may make Promise purists angry:
const createPromise = () => {
let resolver;
return [
new Promise((resolve, reject) => {
resolver = resolve;
}),
resolver,
];
};
const [ promise, resolver ] = createPromise();
promise.then(value => console.log(value));
setTimeout(() => resolver('foo'), 1000);
We are essentially grabbing the reference to the resolve function when the promise is created, and we return that so it can be set externally.
In one second the console will output:
> foo
A helper method would alleviate this extra overhead, and give you the same jQuery feel.
function Deferred() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
Usage would be
const { promise, resolve, reject } = Deferred();
displayConfirmationDialog({
confirm: resolve,
cancel: reject
});
return promise;
Which is similar to jQuery
const dfd = $.Deferred();
displayConfirmationDialog({
confirm: dfd.resolve,
cancel: dfd.reject
});
return dfd.promise();
Although, in a use case this simple, native syntax is fine
return new Promise((resolve, reject) => {
displayConfirmationDialog({
confirm: resolve,
cancel: reject
});
});
I'm using a helper function to create what I call a "flat promise" -
function flatPromise() {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
And I'm using it like so -
function doSomethingAsync() {
// Get your promise and callbacks
const { resolve, reject, promise } = flatPromise();
// Do something amazing...
setTimeout(() => {
resolve('done!');
}, 500);
// Pass your promise to the world
return promise;
}
See full working example -
function flatPromise() {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
function doSomethingAsync() {
// Get your promise and callbacks
const { resolve, reject, promise } = flatPromise();
// Do something amazing...
setTimeout(() => {
resolve('done!');
}, 500);
// Pass your promise to the world
return promise;
}
(async function run() {
const result = await doSomethingAsync()
.catch(err => console.error('rejected with', err));
console.log(result);
})();
Edit:
I have created an NPM package called flat-promise and the code is also available on GitHub.
Just in case somebody came looking for a typescript version of a util simplifying this task:
export const deferred = <T>() => {
let resolve!: (value: T | PromiseLike<T>) => void;
let reject!: (reason?: any) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
return {
resolve,
reject,
promise,
};
};
This can be used eg. like:
const {promise, resolve} = deferred<string>();
promise.then((value) => console.log(value)); // nothing
resolve('foo'); // console.log: foo
You can wrap the Promise in a class.
class Deferred {
constructor(handler) {
this.promise = new Promise((resolve, reject) => {
this.reject = reject;
this.resolve = resolve;
handler(resolve, reject);
});
this.promise.resolve = this.resolve;
this.promise.reject = this.reject;
return this.promise;
}
promise;
resolve;
reject;
}
// How to use.
const promise = new Deferred((resolve, reject) => {
// Use like normal Promise.
});
promise.resolve(); // Resolve from any context.
I find myself missing the Deferred pattern as well in certain cases. You can always create one on top of a ES6 Promise:
export default class Deferred<T> {
private _resolve: (value: T) => void = () => {};
private _reject: (value: T) => void = () => {};
private _promise: Promise<T> = new Promise<T>((resolve, reject) => {
this._reject = reject;
this._resolve = resolve;
})
public get promise(): Promise<T> {
return this._promise;
}
public resolve(value: T) {
this._resolve(value);
}
public reject(value: T) {
this._reject(value);
}
}
Many of the answers here are similar to the last example in this article.
I am caching multiple Promises, and the resolve() and reject() functions can be assigned to any variable or property. As a result I am able to make this code slightly more compact:
function defer(obj) {
obj.promise = new Promise((resolve, reject) => {
obj.resolve = resolve;
obj.reject = reject;
});
}
Here is a simplified example of using this version of defer() to combine a FontFace load Promise with another async process:
function onDOMContentLoaded(evt) {
let all = []; // array of Promises
glob = {}; // global object used elsewhere
defer(glob);
all.push(glob.promise);
// launch async process with callback = resolveGlob()
const myFont = new FontFace("myFont", "url(myFont.woff2)");
document.fonts.add(myFont);
myFont.load();
all.push[myFont];
Promise.all(all).then(() => { runIt(); }, (v) => { alert(v); });
}
//...
function resolveGlob() {
glob.resolve();
}
function runIt() {} // runs after all promises resolved
Update: 2 alternatives in case you want to encapsulate the object:
function defer(obj = {}) {
obj.promise = new Promise((resolve, reject) => {
obj.resolve = resolve;
obj.reject = reject;
});
return obj;
}
let deferred = defer();
and
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
}
let deferred = new Deferred();
Our solution was to use closures to store the resolve/reject functions and additionally attach a function to extend the promise itself.
Here is the pattern:
function getPromise() {
var _resolve, _reject;
var promise = new Promise((resolve, reject) => {
_reject = reject;
_resolve = resolve;
});
promise.resolve_ex = (value) => {
_resolve(value);
};
promise.reject_ex = (value) => {
_reject(value);
};
return promise;
}
And using it:
var promise = getPromise();
promise.then(value => {
console.info('The promise has been fulfilled: ' + value);
});
promise.resolve_ex('hello');
// or the reject version
//promise.reject_ex('goodbye');
Yes, you can. By using the CustomEvent API for the browser environment. And using an event emitter project in node.js environments. Since the snippet in the question is for the browser environment, here is a working example for the same.
function myPromiseReturningFunction(){
return new Promise(resolve => {
window.addEventListener("myCustomEvent", (event) => {
resolve(event.detail);
})
})
}
myPromiseReturningFunction().then(result => {
alert(result)
})
document.getElementById("p").addEventListener("click", () => {
window.dispatchEvent(new CustomEvent("myCustomEvent", {detail : "It works!"}))
})
<p id="p"> Click me </p>
I hope this answer is useful!
Thanks to everyone who posted in this thread. I created a module that includes the Defer() object described earlier as well as a few other objects built upon it. They all leverage Promises and the neat Promise call-back syntax to implement communication/event handling within a program.
Defer: Promise that can be resolved failed remotely (outside of its body)
Delay: Promise that is resolved automatically after a given time
TimeOut: Promise that fails automatically after a given time.
Cycle: Re-triggerable promise to manage events with the Promise syntax
Queue: Execution queue based on Promise chaining.
rp = require("openpromise")
https://github.com/CABrouwers/openpromise
https://www.npmjs.com/package/openpromise
Class version, in Typescript :
export class Deferred<T> {
public readonly promise: Promise<T>
private resolveFn!: (value: T | PromiseLike<T>) => void
private rejectFn!: (reason?: any) => void
public constructor() {
this.promise = new Promise<T>((resolve, reject) => {
this.resolveFn = resolve
this.rejectFn = reject
})
}
public reject(reason?: any): void {
this.rejectFn(reason)
}
public resolve(param: T): void {
this.resolveFn(param)
}
}
I wrote a small lib for this. https://www.npmjs.com/package/#inf3rno/promise.exposed
I used the factory method approach others wrote, but I overrode the then, catch, finally methods too, so you can resolve the original promise by those as well.
Resolving Promise without executor from outside:
const promise = Promise.exposed().then(console.log);
promise.resolve("This should show up in the console.");
Racing with the executor's setTimeout from outside:
const promise = Promise.exposed(function (resolve, reject){
setTimeout(function (){
resolve("I almost fell asleep.")
}, 100000);
}).then(console.log);
setTimeout(function (){
promise.resolve("I don't want to wait that much.");
}, 100);
There is a no-conflict mode if you don't want to pollute the global namespace:
const createExposedPromise = require("#inf3rno/promise.exposed/noConflict");
const promise = createExposedPromise().then(console.log);
promise.resolve("This should show up in the console.");
I made a library called manual-promise that functions as a drop in replacement for Promise. None of the other answers here will work as drop in replacements for Promise, as they use proxies or wrappers.
yarn add manual-promise
npn install manual-promise
import { ManualPromise } from "manual-promise";
const prom = new ManualPromise();
prom.resolve(2);
// actions can still be run inside the promise
const prom2 = new ManualPromise((resolve, reject) => {
// ... code
});
new ManualPromise() instanceof Promise === true
https://github.com/zpxp/manual-promise#readme
Just another solution to resolve Promise from the outside
class Lock {
#lock; // Promise to be resolved (on release)
release; // Release lock
id; // Id of lock
constructor(id) {
this.id = id
this.#lock = new Promise((resolve) => {
this.release = () => {
if (resolve) {
resolve()
} else {
Promise.resolve()
}
}
})
}
get() { return this.#lock }
}
Usage
let lock = new Lock(... some id ...);
...
lock.get().then(()=>{console.log('resolved/released')})
lock.release() // Excpected 'resolved/released'
How about creating a function to hijack the reject and return it ?
function createRejectablePromise(handler) {
let _reject;
const promise = new Promise((resolve, reject) => {
_reject = reject;
handler(resolve, reject);
})
promise.reject = _reject;
return promise;
}
// Usage
const { reject } = createRejectablePromise((resolve) => {
setTimeout(() => {
console.log('resolved')
resolve();
}, 2000)
});
reject();
I've put together a gist that does that job: https://gist.github.com/thiagoh/c24310b562d50a14f3e7602a82b4ef13
here's how you should use it:
import ExternalizedPromiseCreator from '../externalized-promise';
describe('ExternalizedPromise', () => {
let fn: jest.Mock;
let deferredFn: jest.Mock;
let neverCalledFn: jest.Mock;
beforeEach(() => {
fn = jest.fn();
deferredFn = jest.fn();
neverCalledFn = jest.fn();
});
it('resolve should resolve the promise', done => {
const externalizedPromise = ExternalizedPromiseCreator.create(() => fn());
externalizedPromise
.promise
.then(() => deferredFn())
.catch(() => neverCalledFn())
.then(() => {
expect(deferredFn).toHaveBeenCalled();
expect(neverCalledFn).not.toHaveBeenCalled();
done();
});
expect(fn).toHaveBeenCalled();
expect(neverCalledFn).not.toHaveBeenCalled();
expect(deferredFn).not.toHaveBeenCalled();
externalizedPromise.resolve();
});
...
});
As I didn't find what I was looking for, I will share what I actually wanted to achieve when I ended in this question.
Scenario: I have 3 different API's with same possible response and therefore I would like to handle the completion and error handling of the promises in a single function. This is what I did:
Create a handler function:
private handleHttpPromise = (promise: Promise<any>) => {
promise
.then((response: any) => {
// do something with the response
console.log(response);
})
.catch((error) => {
// do something with the error
console.log(error);
});
};
Send your promises to the created handler
switch (method) {
case 'get': {
this.handleHttpPromise(apiService.get(url));
break;
}
case 'post': {
if (jsonData) {
this.handleHttpPromise(apiService.post(url, jsonData));
}
break;
}
// (...)
}
I would like to share something different, an extension to this topic.
Sometimes you want a "task promise" to be automatically re-created at the same address (property or variable) when it resolves. It's possible to create an outside resolver that does just that.
Example of a recurring promise with an external resolver. Whenever the resolver is called, a new promise is created at the same address/variable/property.
let resolvePromise;
let thePromise;
const setPromise = (resolve) => {
resolvePromise = () => {
resolve();
thePromise = new Promise(setPromise);
}
}
thePromise = new Promise(setPromise);
(async () => {
let i = 0;
while (true) {
let msg = (i % 2 === 0) ? 'Tick' : 'Tock';
document.body.innerHTML = msg;
setTimeout(resolvePromise, 1000);
await thePromise;
i++;
}
})();
https://jsfiddle.net/h3zvw5xr
If (like me) you don't like augmenting native instances, nor unwieldy ".promise" properties ... but do love proxies and mangling classes, then this one is for you:
class GroovyPromise {
constructor() {
return new Proxy(new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
}), {
get: (target, prop) =>
this[prop] || target[prop].bind(target),
});
}
}
Used like so:
const groovypromise = new GroovyPromise();
setTimeout(() => groovypromise.resolve('groovy'), 1000);
console.log(await groovypromise);
Of course you can also rename the class to something dull like "Deferred"
For fun, you also combine a promise into a self-resolvable function:
function Resolver() {
let resolve;
const promise = new Promise(r => resolve = r);
return new Proxy(resolve, {
get: (_, prop) => promise[prop].bind(promise)
});
}
const resolve = Resolver();
(async () => {
resolve
.then(value => console.log('thenable:', value))
.finally(() => console.log('finally'));
const value = await resolve;
console.log('awaitable:', value);
})()
resolve('test');
// thenable: test
// finally
// awaitable: test
first enable --allow-natives-syntax on browser or node
const p = new Promise(function(resolve, reject){
if (someCondition){
resolve();
} else {
reject();
}
});
onClick = function () {
%ResolvePromise(p, value)
}
Related
Anticipated FAQ:
Yes, I know what a Promise is.
No, I can't simply move the init logic to the constructor. It needs to be called in the initMethod because the initMethod is a hook that needs to be called at a certain time.
Sorry, it's just that I saw some similar questions marked as "duplicate", so I wanted to put these FAQ at the top.
Question
My issue is the following race condition:
class Service {
private x: string | null = null;
initMethod() {
this.x = 'hello';
}
async methodA() {
return this.x.length;
}
}
const service = new Service();
setTimeout(() => service.initMethod(), 1000);
service.methodA().catch(console.log);
TypeError: Cannot read properties of null (reading 'length')
at Service.methodA (<anonymous>:15:19)
at <anonymous>:20:9
at dn (<anonymous>:16:5449)
I need something like a Promise whose settled value can be set from another part of the code. Something like:
class Service {
private x: SettablePromise<string> = new SettablePromise();
initMethod() {
this.x.set('hello');
}
async methodA() {
return (await this.x).length;
}
}
const service = new Service();
setTimeout(() => service.initMethod(), 1000);
service.methodA().catch(console.log);
The best I can come up with is to make a class that polls a value until it turns non-null. I'm hoping there's something smarter. I don't want to have to fine-tune a poll interval.
Edits
Sorry for the initial confusing example. The race condition is that methodA can be called before initMethod.
There was also an unnecessary async in the initMethod. I just made it async because the real method it was based on is async.
In the following example, you can run the init before or after the async method call. Either will work -
const s = new Service()
// init
s.init()
// then query
s.query("SELECT * FROM evil").then(console.log)
const s = new Service()
// query first
s.query("SELECT * FROM evil").then(console.log)
// then init
s.init()
deferred
The solution begins with a generic deferred value that allows us to externally resolve or reject a promise -
function deferred() {
let resolve, reject
const promise = new Promise((res,rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
service
Now we will write Service which has a resource deferred value. The init method will resolve the resource at some point in time. The asynchronous method query will await the resource before it proceeds -
class Service {
resource = deferred() // deferred resource
async init() {
this.resource.resolve(await connect()) // resolve resource
}
async query(input) {
const db = await this.resource.promise // await resource
return db.query(input)
}
}
connect
This is just some example operation that we run in the init method. It returns an object with a query method that mocks a database call -
async function connect() {
await sleep(2000) // fake delay
return {
query: (input) => {
console.log("running query:", input)
return ["hello", "world"] // mock data result
}
}
}
function sleep(ms) {
return new Promise(r => setTimeout(r, ms))
}
demo
function deferred() {
let resolve, reject
const promise = new Promise((res,rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
class Service {
resource = deferred()
async init() {
this.resource.resolve(await connect())
}
async query(input) {
const db = await this.resource.promise
return db.query(input)
}
}
async function connect() {
await sleep(2000)
return {
query: (input) => {
console.log("running query:", input)
return ["hello", "world"]
}
}
}
function sleep(ms) {
return new Promise(r => setTimeout(r, ms))
}
const s = new Service()
s.query("SELECT * FROM evil").then(console.log)
s.init()
always handle rejections
If init fails to connect to the database, we need to reflect that with the resource, otherwise our program will hang indefinitely -
class Service {
resource = deferred()
async init() {
try {
const db = await timeout(connect(), 5000) // timeout
this.resource.resolve(db)
}
catch (err) {
this.resource.reject(err) // reject error
}
}
async query(input) {
const db = await timeout(this.resource.promise, 5000) // timeout
return db.query(input)
}
}
function timeout(p, ms) {
return Promise.race([
p,
sleep(ms).then(() => { throw Error("timeout") }),
])
}
As I understand it, you need to have a promise settled within constructor but it have to be resolved only when initMethod is called.
You can expose a promise resolver alongside the promise :
class Service {
private x: string | null = null;
private promise;
private resolve;
constructor() {
this.promise = new Promise(resolve => this.resolve = resolve);
}
async initMethod() {
// Do your async stuff
await new Promise(resolve => setTimeout(resolve, 1000));
this.x = 'hello';
// And resolve Service promise
this.resolve();
}
async methodA() {
await this.promise;
return this.x.length;
}
}
See Resolve Javascript Promise outside the Promise constructor scope for more examples.
You need to initialise a property with a Promise value that only resolves after initMethod() has completed.
This involves also maintaining the promise's resolve callback as a class property.
class Service {
#initResolve;
#initPromise = new Promise((resolve) => {
this.#initResolve = resolve;
});
#x = null;
async initMethod() {
await new Promise(resolve => setTimeout(resolve, 1000));
this.#x = 'hello';
this.#initResolve(); // resolve #initPromise
}
async methodA() {
await this.#initPromise;
return this.#x.length;
}
}
const service = new Service();
console.log("methodA: start");
service.methodA().then(console.log.bind(console, "methodA: end:"));
setTimeout(async () => {
console.log("initMethod: start");
await service.initMethod()
console.log("initMethod: end");
}, 1000);
Note: Using JavaScript private class features for the Snippet but I'm sure you can translate it to Typescript.
here is a code example:
var promise = new Promise((resolve, reject) => {
resolve("resolved");
});
promise.abort = function () {
console.log("abort!");
};
console.log(promise.abort());
function bar() {
return promise.then((value) => {
return value + "!";
});
}
newPromise = bar();
newPromise.then(value => {
console.log(value);
})
console.log(newPromise.abort());
i added a custom function to a promise. call the function abort() works like expected.
in the function bar() i use the then() method to log out the resolved value.
i know that the return value of bar() is a new promise. but it loses the custom function abort().
how can i inheritance the custom function to the new promise?
Create your own class and subclass the native Promise. Then you can keep custom methods as .then() will return the custom class
class MyPromise extends Promise {
abort() {
console.log("abort!");
}
}
var promise = new MyPromise((resolve, reject) => {
resolve("resolved");
});
console.log(promise.abort());
function bar() {
return promise.then((value) => {
console.log(value);
});
}
newPromise = bar();
console.log(newPromise.abort());
You cannot cancel/abort a Promise. One approach is to write a generic timeout or similar function to handle a long withstanding Promise -
function sleep(ms) {
return new Promise(r => setTimeout(r, ms))
}
function timeout(p, ms) {
const orFail = sleep(ms).then(_ => { throw Error("timeout") })
return Promise.race([ p, orFail ])
}
async function testTask(value) {
await sleep(3000)
return value
}
timeout(testTask("hello"), 5000)
.then(console.log, console.error) // "hello"
timeout(testTask("world"), 1000)
.then(console.log, console.error) // Error "timeout"
Another approach is to use a third-party library like bluebird that supports cancellation -
import { Promise } from "bluebird"
function makeCancellableRequest(url) {
return new Promise(function(resolve, reject, onCancel) {
var xhr = new XMLHttpRequest();
xhr.on("load", resolve);
xhr.on("error", reject);
xhr.open("GET", url, true);
xhr.send(null);
// Note the onCancel argument only exists if cancellation has been enabled!
onCancel(function() {
xhr.abort();
});
});
}
I've got a Promise function
function test()
{
let promise = new Promise<string>(function(resolve, reject)
{
func( resolve, reject );
});
return promise;
}
function func(resolve, reject )
{
let reject2 = reject;
window.on( "error", (msg) =>
{
console.log("inside error");
reject2();
} );
// other stuff
}
In an error condition - I'm trying to reject the original promise.
It seems to work - but evey time I create the error condition, the "inside error" message gets printed that many times.
Thanks.
I think you want to remove the handler after it fires.
Something like this:
function test()
{
let promise = new Promise<string>(function(resolve, reject)
{
func( resolve, reject );
});
return promise;
}
function func(resolve, reject )
{
let reject2 = reject;
let handler = (msg) =>
{
console.log("inside error");
reject2();
window.off( "error", handler ); //removing the handler here
}
window.on( "error", handler);
// other stuff
}
But this approach has the problem that will remove all registered handlers at any error and I don't know if this is desired.
I don't know what you want to do, my guess was too long to put in comments, so give this a shot. Quite sure this is an A->B->C problem.
!function(){
let errorAttached = false,
currentReject = null;
function test()
{
let promise = new Promise(function(resolve, reject)
{
func( resolve, reject );
});
return promise;
}
function func(resolve, reject )
{
let currentReject = reject;
if(!errorAttached) {
window.on( "error", (msg) =>
{
console.log("inside error");
currentReject();
});
errorAttached = true;
}
// other stuff
}
}();
I did not understand why you are creating a callback function to treat the result of your promise. I've never used this way. Perhaps you want to cancel your promise when something happens to the page. In this case, you could follow the example on this page. You will have a bunch of way to implement it.
https://blog.bloomca.me/2017/12/04/how-to-cancel-your-promise.html
class CancelablePromise {
constructor(executor) {
let _reject = null;
const cancelablePromise = new Promise((resolve, reject) => {
_reject = reject;
return executor(resolve, reject);
});
cancelablePromise.cancel = _reject;
return cancelablePromise;
}
}
// now lets work with the class
var cancelable = false;
const p = new CancelablePromise((resolve, reject) => {
setTimeout(() => {
if(!cancelable)
resolve(console.log('resolved!'));
}, 2000);
})
p.catch(error => console.log(error.toString()));
setTimeout(() => {
cancelable = true;
p.cancel(new Error("Whoops!"));
}, 1000); // change by 3000 to be resolved
How can I implement Promise.race() method with async and await?
async function promiseRace(promises) {
const results = [];
for (const p of promises) {
await p;
results.push(p);
}
return results[0];
}
I've tried to implement it like above but this doesn't work.
You can't. When using await you halt execution onto one specific promise. To implement Promise.race manually, you have to fiddle with callbacks:
function race(promises) {
return new Promise((resolve, reject) => {
for(const promise of promises)
promise.then(resolve, reject);
});
}
You can't. Just like you cannot implement the Promise constructor using async/await. Remember that await is only syntactic sugar for then calls - and you cannot implement the basic promise combinators using only that.
You can by using a wrapper promise along with async await. In the wrapper promise, protect the resolve/reject so that only the first promise wins.
Promise.race example using async/await:
// Implements promise.race
const race = async (promises) => {
// Create a promise that resolves as soon as
// any of the promises passed in resolve or reject.
const raceResultPromise = new Promise((resolve, reject) => {
// Keep track of whether we've heard back from any promise yet.
let resolved = false;
// Protect the resolve call so that only the first
// promise can resolve the race.
const resolver = (promisedVal) => {
if (resolved) {
return;
}
resolved = true;
resolve(promisedVal);
};
// Protect the rejects too because they can end the race.
const rejector = (promisedErr) => {
if (resolved) {
return;
}
resolved = true;
reject(promisedErr);
};
// Place the promises in the race, each can
// call the resolver, but the resolver only
// allows the first to win.
promises.forEach(async (promise) => {
try {
const promisedVal = await promise;
resolver(promisedVal);
} catch (e) {
rejector(e);
}
});
});
return raceResultPromise;
};
// *************
// Test Methods
// *************
const fetch = async (millis) => {
await waitMillis(millis);
return 'Async result: ' + millis + ' millis.';
};
const waitMillis = (millis) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, millis);
});
};
const run = async () => {
let result;
result = await race([fetch(1), fetch(2), fetch(3)]);
console.log('Winner', result);
result = await race([fetch(3), fetch(2), fetch(1)]);
console.log('Winner', result);
result = await race([fetch(10), fetch(3), fetch(4)]);
console.log('Winner', result);
};
run();
Why not:
const race = async (promiseArr) => {
return Promise.race(promiseArr)
}
And inside your async function:
let dayAtTheRace = await race([
my.promiseFunc(),
my.wait(10)
])
function promiseRace(promises) {
return new Promise((resolve, reject) => {
promises.forEach(async (promise) => {
try {
const result = await promise;
resolve(result);
} catch (err) {
reject(err);
}
});
});
Here is my solution:
async function promiseRace(promises) {
const results = [];
for (const p of promises) {
results.push(await p);
}
return results[0];
}
I'm looking at both PromiseJS and ES6 for something similar to a CompletableFuture, but couldn't find any.
Any suggestions how this can be achieved in javascript? Thanks
Note: Promise.resolve() isn't suitable, unless you can create the Promise object first and complete it later.
Update
As all answers pointed out, the correct way is to use Promise's constructor:
new Promise((resolve, reject) => { resolve(data); })
Note: Promise.resolve() isn't suitable, unless you can create the
Promise object first and complete it later.
You can use Promise constructor, pass onFulfilled, onRejected arguments outside scope of executor function
var complete, err, now = new Date().getTime();
var promise = new Promise((onFulfilled, onRejected) => {
complete = onFulfilled; err = onRejected;
});
promise.then((data) => {
console.log(data)
});
setTimeout(() => {
complete("promise resolved "
+ (new Date().getTime() - now)
+ " in the future")
}, Math.random() * 3500)
There is no deferred-like API in JavaScript for good reason. You don't have a CompletableFuture with a .complete method, instead you just use the new Promise constructor. You already linked some documentation containing examples so I'm not going to repeat them here.
Just meet the same need, this is how I do this in TypeScript
export function createLazyPromise<T = any>(): Promise<T> & { reject: () => void, resolve: (v: T) => void } {
let onResolve, onReject;
const promise = new Promise<T>(((resolve, reject) => {
onResolve = resolve;
onReject = reject
}));
promise['resolve'] = onResolve;
promise['reject'] = onReject;
return promise as any
}
Usee like this
test('test shell', async () => {
// resolve later
const promise = createLazyPromise();
const result = shell.exec(
'ps aux | head -3',
{
silent: true,
},
(code, stdout, stderr) => {
promise.resolve({code, stdout, stderr});
}
);
console.log(result.pid);
console.log(await promise);
});