Es6 Promise Settled Callback

ES6 promise settled callback?

Isn't there a .always like jQuery has?

No, there's not (yet). Though there is an active proposal, so maybe ES2018.

Yes, there is: promise .finally() is part of the standard since ES2018.

If not, how do I achieve this?

You can implement the finally method yourself like this:

Promise.prototype.finally = function(cb) {
const res = () => this
const fin = () => Promise.resolve(cb()).then(res)
return this.then(fin, fin);
};

or more extensively, with passing resolution information to the callback:

Promise.prototype.finally = function(cb) {
const res = () => this
return this.then(value =>
Promise.resolve(cb({state:"fulfilled", value})).then(res)
, reason =>
Promise.resolve(cb({state:"rejected", reason})).then(res)
);
};

Both ensure that the original resolution is sustained (when there is no exception in the callback) and that promises are awaited.

JavaScript: Promise callback execution

The promise executor function is the function you pass to new Promise. It is executed synchronously so it can start whatever asynchronous process the promise represents.

The callbacks you attach with then, catch, and finally are always called asynchronously, whether the promise is already settled or not.

So in your example, console.log("After resolving the promise"); is called before the console.log you've passed to then.

Here's an example showing that more clearly:

let myPromise = new Promise((resolve, reject) => {    console.log("In the executor function");    resolve("Resolved from the promise");});myPromise.then(result => {    console.log("In the fulfillment handler: " + result);});
console.log("After resolving the promise");

ES6 Javascript Promise - execute after .then() is called

Is it possible to do the same thing with an ES6 Promise from within the scope of the function?

No, this isn't possible. then callbacks always run asynchronously, and that includes being asynchronous in regard to the resolve() call.

(That said, promise callbacks are queued, so you can abuse that queue to get your code behind the other:

function demoPromise() {
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
p.then(() => {
console.log("I execute second");
}); // because I will be scheduled second
}, 1000);
});
return p;
}

demoPromise().then(() => {
console.log("I execute first");
}); // because I was scheduled first

But please don't do that)

If you want to execute code after a callback is called in JavaScript

then you probably should not just return a promise. Take a callback that does what you want before executing your code:

function demoPromise(callback) {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
}).then(() => {
return callback();
}).then(res => {
console.log("I execute second");
});
}

demoPromise(() => {
console.log("I execute first");
}).then(() => {
console.log("I execute last");
});

This is known as the disposer pattern and very useful for handling resources.

ES6 Promise.all progress

I've knocked up a little helper function that you can re-use.

Basically pass your promises as normal, and provide a callback to do what you want with the progress..

function allProgress(proms, progress_cb) {  let d = 0;  progress_cb(0);  for (const p of proms) {    p.then(()=> {          d ++;      progress_cb( (d * 100) / proms.length );    });  }  return Promise.all(proms);}
function test(ms) { return new Promise((resolve) => { setTimeout(() => { console.log(`Waited ${ms}`); resolve(); }, ms); });}

allProgress([test(1000), test(3000), test(2000), test(3500)], (p) => { console.log(`% Done = ${p.toFixed(2)}`);});

Why do both Promise's then & catch callbacks get called?

The then callback gets called because the catch callback is before it, not after. The rejection has already been handled by catch. If you change the the order (i.e. (promise.then(...).catch(...))), the then callback won't be executed.

MDN says that the .catch() method "returns a new promise resolving to the return value of the callback". Your catch callback doesn't return anything, so the promise is resolved with undefined value.

How JavaScript promises work behind the scenes

The following is a simplified implementation of the built-in Promise class. catch and finally have not been implemented.

The function supplied to the Promise constructor is called the executor function, and is invoked immediately and synchronously.

Every promise has a method .then, enabling the chaining of promises.

Functions supplied to .then are always invoked asynchronously on a microtask (note use of queueMicrotask below).

Every time .then is called, a new promise is created and returned.

.then can be called more than once on the same promise, creating a multicast of the result of the promise, and a branching of the promise chain.

A promise can be in one of three states: pending, fulfilled, or rejected. State transitions are unidirectional: you cannot move from fulfilled or rejected, back to pending.

If a promise is resolved with another promise, then the two promise chains are joined and the outer promise takes on the status of the inner promise (which could be pending), until the inner promise resolves.

function Promise(executor) {  if (!executor) throw "Promise executor undefined"  let status = "pending", value, thenQ = []
const then = onFulfilled => { let resolver // This ensures control does not move to later promises // until prior promises have been resolved. const nextPromise = new Promise(resolve => (resolver = resolve)) // More than one "then" can be registered with each promise. thenQ.push((...args) => resolver(onFulfilled(...args))) return nextPromise }
// We check if the result is a "thenable"; if so, we treat // it as an inner promise, otherwise we simply fulfil with // the result. const resolve = result => result?.then ? result.then(fulfil) : fulfil(result)
// When a promise has been fulfilled, its "thens" can be run. const fulfil = result => (status = "fulfilled", value = result, executeThens(value))
// "Thens" are run asynchronously, on a microtask. const executeThens = value => queueMicrotask(() => thenQ.forEach(el => el(value)))
// The executor is run synchronously. executor(resolve)
return { then, get status() { return status }, get value() { return value } }}
// Chainingnew Promise(resolve => { console.log('Waiting for step 1...') setTimeout(() => resolve("One, two..."), 1500)}).then(result => new Promise(resolve => { console.log('Waiting for step 2...') setTimeout(() => resolve(`${result}three, four`), 1500)})).then(result => console.log(`Chaining result: ${result}.`))
// Branchingconst p = new Promise(resolve => { console.log('Waiting for step a...') setTimeout(() => resolve("Alpha, Bravo..."), 1500)})
p.then(result => new Promise(resolve => { console.log('Waiting for step b1...') setTimeout(() => resolve(`${result}Charlie, Delta`), 1500)})).then(console.log)
p.then(result => { console.log('Waiting for step b2...') return `${result}Echo, Foxtrot`}).then(console.log)

Resolve Javascript Promise outside the Promise constructor scope

simple:

var promiseResolve, promiseReject;

var promise = new Promise(function(resolve, reject){
promiseResolve = resolve;
promiseReject = reject;
});

promiseResolve();

Why does javascript ES6 Promises continue execution after a resolve?

JavaScript has the concept of "run to completion". Unless an error is thrown, a function is executed until a return statement or its end is reached. Other code outside of the function can't interfere with that (unless, again, an error is thrown).

If you want resolve() to exit your initializer function, you have to prepend it by return:

return new Promise(function(resolve, reject) {
return resolve();
console.log("Not doing more stuff after a return statement");
});


Related Topics



Leave a reply



Submit