Are JavaScript Promise asynchronous? - javascript

Just a quick question of clarifications: is JavaScript Promise asynchronous? I've been reading a lot of posts on Promise and async programming (namely ajax requests). If Promise is not async, how do we make it so?
For example, I have a function to wrap a function f with argument array args inside a Promise. Nothing about f inherently is async.
function getPromise(f, args) {
return new Promise(function(resolve, reject) {
var result = f.apply(undefined, args);
resolve(result);
});
}
To make this async, I read some SO posts and decided that the setTimeout is what a lot of people were recommending to make code non-blocking.
function getPromise(f, args) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
var r = f.apply(undefined, args);
resolve(r);
}, 0);
});
}
Would this approach with setTimeout work to make code non-blocking inside a Promise?
(Note that I am not relying on any third-party Promise API, just what is supported by the browsers).

I think you are working under a misunderstanding. JavaScript code is always* blocking; that is because it runs on a single thread. The advantages of the asynchronous style of coding in Javascript is that external operations like I/O do not require blocking that thread. The callback that processes the response from the I/O is still blocking though and no other JavaScript can run concurrently.
* Unless you consider running multiple processes (or WebWorkers in a browser context).
Now for your specific questions:
Just a quick question of clarifications: is JavaScript Promise asynchronous?
No, the callback passed into the Promise constructor is executed immediately and synchronously, though it is definitely possible to start an asynchronous task, such as a timeout or writing to a file and wait until that asynchronous task has completed before resolving the promise; in fact that is the primary use-case of promises.
Would this approach with setTimeout work to make code non-blocking inside a Promise?
No, all it does is change the order of execution. The rest of your script will execute until completion and then when there is nothing more for it to do the callback for setTimeout will be executed.
For clarification:
console.log( 'a' );
new Promise( function ( ) {
console.log( 'b' );
setTimeout( function ( ) {
console.log( 'D' );
}, 0 );
} );
// Other synchronous stuff, that possibly takes a very long time to process
console.log( 'c' );
The above program deterministically prints:
a
b
c
D
That is because the callback for the setTimeout won't execute until the main thread has nothing left to do (after logging 'c').

const p = new Promise((resolve, reject) => {
if (1 + 1 === 2) {
resolve("A");
} else {
reject("B");
}
});
p.then((name) => console.log(name)).catch((name) => console.log(name));
console.log("hello world");
Promise doesn't block the next lines while it's in pending state. So, it works asynchronously.

Your MDN reference was helpful. Thx.
If you run this, you should see
asynchronous output.
================================================================
asynchronous using "Promise"
const log = console.log;
//---------------------------------------
class PromiseLab {
play_promise_chain(start) {
//"then" returns a promise, so we can chain
const promise = new Promise((resolve, reject) => {
resolve(start);
});
promise.then((start) => {
log(`Value: "${start}" -- adding one`);
return start + 1;
}).then((start) => {
log(`Value: "${start}" -- adding two`);
return start + 2;
}).then((start) => {
log(`Value: "${start}" -- adding three`);
return start + 3;
}).catch((error) => {
if (error) log(error);
});
}
}
//---------------------------------------
const lab = new PromiseLab();
lab.play_promise_chain(100);
lab.play_promise_chain(200);
Output should be asynchronous something like:
Value: "100" -- adding one
Value: "200" -- adding one
Value: "101" -- adding two
Value: "201" -- adding two
Value: "103" -- adding three
Value: "203" -- adding three
================================================================
Synchronous using "MyPromise" (e.g. basic js code)
const log = console.log;
//---------------------------------------
class MyPromise {
value(value) { this.value = value; }
error(err) { this.error = err; }
constructor(twoArgFct) {
twoArgFct(
aValue => this.value(aValue),
anError => this.error(anError));
}
then(resultHandler) {
const result = resultHandler(this.value);
return new MyPromise((resolve, reject) => {
resolve(result);
});
}
catch(errorHandler) {
errorHandler(this.error());
}
}
//--------------------------------------
class MyPromiseLab {
play_promise_chain(start) {
//"then" returns a promise, so we can chain
const promise = new MyPromise((resolve, reject) => {
resolve(start);
});
promise.then((start) => {
log(`Value: "${start}" -- adding one`);
return start + 1;
}).then((start) => {
log(`Value: "${start}" -- adding two`);
return start + 2;
}).then((start) => {
log(`Value: "${start}" -- adding three`);
return start + 3;
}).catch((error) => {
if (error) log(error);
});
}
}
//---------------------------------------
const lab = new MyPromiseLab();
lab.play_promise_chain(100);
lab.play_promise_chain(200);
Output should be synchronous:
Value: "100" -- adding one
Value: "101" -- adding two
Value: "103" -- adding three
Value: "200" -- adding one
Value: "201" -- adding two
Value: "203" -- adding three

Related

Promise.resolve vs Promise.resolve().then()

A question asked here before, with the exact same title as this one, was answered with a "You should not use that, use this instead", I am looking to know what it does, not what else could I do, it's about understanding not a simple copy a paste.
My question is quite simple, what is the difference between these three approaches when creating a promise?
const API = (item, fail) =>
new Promise((resolve, reject) => {
if (fail) reject(item + ' ...with an error');
setTimeout(() => resolve(item), 1000);
});
(async () => {
const pro1 = Promise.resolve(API('I am inside resolve'));
const pro2 = Promise.resolve(API('I am inside resolve', true));
const pro3 = Promise.resolve().then(() => API('I am thenable'));
const pro4 = Promise.resolve().then(() => API('I am thenable', true));
const pro5 = new Promise((resolve) => resolve(API('I am a new promise')));
const pro6 = new Promise((resolve) => resolve(API('I am a new promise', true)));
const store = [pro1, pro2, pro3, pro4, pro5, pro6];
const results = await Promise.allSettled(store);
for (const { status, value, reason } of results) {
if (status === 'fulfilled') console.log(value)
else console.log(reason)
}
})();
The difference is in job to be done. While all of this methods are valid, they have different cost and predictability.
Promise.resolve() produces single resolved Promise instance, and depending on value provided to the call JS engine have information to optimize it. It makes all work to be done in a single call to underlying code of the JS engine (usually C++, but could be Java or WASM). So it's always the best choice.
Promise.resolve().then(() => API(/*...*/)) Produce several Promise instances: one at Promise.resolve() and other at .then() call. It also allocates more memory and make several (3 or more) redundant jumps between JS and the engine. It's hardly optimizable and requires intensive heuristics to be performed to figure out is this call optimizable. It's the worst option.
new Promise((resolve) => resolve(API(/* ... */)) allocates one function and one Promise instance and makes two jumps between JS and the engine. It's harder to optimize this call, due to nature of JS.
Promise.resolve().then()
In your examples, the then() makes no difference as you just resolve the promise, and get its data.
then() is typically used to chain promises, take this as an example:
Promise.resolve('foo')
// 1. Receive "foo", concatenate "bar" to it, and resolve that to the next then
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1);
});
})
// 2. receive "foobar", register a callback function to work on that string
// and print it to the console, but not before returning the unworked on
// string to the next then
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string); // foobarbaz
}, 1)
return string;
})
Here we chain multiple promises then() off of a previously resolved promise, while maintaining the original data from the first resolve, though in this case we modify it with every new promise.
You can read more about promises and chaining here.

How to create a queue of promises that will be sync when it's empty?

I have this problem in the jQuery Terminal library. I have an echo method that prints the stuff on the terminal and you can print a string, promise, or function that returns a promise or string (to simplify let's assume string or promise).
But the issue is that if you echo a few promises and strings they are not printed in order. The code was just waiting with the next echo until the promise was resolved. The problem is that it only works for one promise.
So I was thinking that I need a kind of data structure that will keep adding promises and it will wait for all promises. But I'm not sure how to do this.
The problem I have is that I can't just chain promises because the echo method needs to be synchronous when there is nothing in a queue and you print a string. But this is not how Promise A+ behaves they are always async (even Promise.resolve()). I have a lot of unit tests that rely on echo being synchronous and it will be break change and I don't want that.
My idea was to just create an array of promises but I'm not sure when I should remove the promise from the array so the queue can be empty when all promises are resolved and I can do synchronous call.
Something like:
class PromiseQueue {
constructor() {
this._promises = [];
}
add(promise) {
this._promises.push(promise);
}
empty() {
return !this._promises.length;
}
then(fn) {
if (this.empty()) {
fn();
} else {
Promise.all(this._promises).then(function() {
// what do do with this._promises?
fn();
});
}
}
}
I guess it's not that simple as in my attempt. I have no idea how to implement this behavior.
EDIT:
I have this two cases that I want to handle:
function render(text, delay) {
return new Promise(resolve => {
setTimeout(() => resolve(text), delay);
});
}
term.echo(() => render('lorem', 1000));
term.echo('foo');
term.echo(() => render('ipsum', 1000));
term.echo('bar');
term.echo(() => render('dolor', 1000));
term.echo('baz');
setTimeout(function() {
// this should render immediately because all promises
// would be already resolved after 5 seconds
term.echo('lorem ipsum');
// so after the call I check the DOM and see the output
// this is important for unit tests and will be huge
// breaking change if echo don't render string synchronously
}, 5000);
NOTE: echo promise and function that return a promise in this example is the same the only difference is that function is re-invoked in each re-render (e.g. when browser or container is resized).
Another example is just:
term.echo('foo');
term.echo('bar');
term.echo('baz');
that should be also synced. I need a generic solution so you don't need to know exactly what echo is doing.
I would not even use Promise.all here - wait only for the first promise in the queue.
const term = {
/** an array while a promise is currently awaited, null when `echo` can be synchronous */
_queue: null,
echo(value) {
if (this._queue) {
this._queue.push(value);
} else {
this._echo(value);
}
},
/** returns a promise if the `value` is asynchronous, undefined otherwise */
_echo(value) {
try {
if (typeof value == "function") {
value = value();
}
if (typeof value.then == "function") {
this._queue ??= [];
return Promise.resolve(value).then(console.log, console.error).finally(() => {
while (this._queue.length) {
if (this._echo(this._queue.shift())) {
return;
}
}
this._queue = null;
});
} else {
console.log(value);
}
} catch(err) {
console.error(err);
}
}
};
function render(text, delay) {
return new Promise(resolve => {
setTimeout(() => resolve(text), delay);
});
}
term.echo('foo');
term.echo(() => render('lorem', 1000));
term.echo('bar');
term.echo(() => render('ipsum', 1000));
term.echo('baz');
term.echo(() => render('dolor', 1000));
term.echo('quam');
setTimeout(function() {
// this should render immediately because all promises
// would be already resolved after 5 seconds
term.echo('lorem ipsum');
console.log('end');
}, 5000);
console.log('echos queued');
While I was editing the question I've realized that this is similar to exec behavior:
term.exec('timer --time 1000 "hello"');
term.exec('echo world');
term.exec('timer --time 1000 "hello"');
term.exec('echo world');
and I solve this using same mechanism that was proved to work.
I've added a flag:
if (is_promise(next)) {
echo_promise = true;
}
similar to paused flag.
Then when promise next is resolved. I used the same what was done in resume()
unpromise(next, function() {
echo_promise = false;
var original = echo_delay;
echo_delay = [];
for (var i = 0; i < original.length; ++i) {
self.echo.apply(self, original[i]);
}
});
unpromise is a function that I always use. It invokes the function as then callback or calls immediately. So it's sync by default but async when needed. You can find the code on GitHub jquery.terminal-src.js#L1072.
And then last thing in echo main code:
if (echo_promise) {
echo_delay.push([arg, options]);
} else {
echo(arg);
}
This is not very clean code because echo is invoked multiple times but it works. If you know a better solution please share.
Maybe this kind of code can be abstracted into single PromiseQueue interface.

Resolve promise on array push - javascript

I'm attempting to define a function that returns a promise. The promise should resolve when a given array is set (push()).
To do this I'm attempting to use a Proxy object (influenced by this):
let a = []
;(async function(){
const observe = array => new Promise(resolve =>
new Proxy(array, {
set(array, key, val) {
array[key] = val;
resolve();
}
}));
while(true){
await observe(a);
console.log(new Date().toLocaleTimeString(),"Blimey Guv'nor:",`${a.pop()}`);
}
})(a);
;(async function(){
await new Promise(resolve => timerID = setTimeout(resolve, 2000))
a.push('ʕ·͡ᴥ·ʔ');
a.push('¯\(°_o)/¯ ')
})(a)
I can't see why this doesn't work. Does anyone have any idea?
More generally, what is a good way to have a promise resolve on push to an array?
The problems with your attempt:
you invoke .push on the original array, not the proxied one. Where you create the proxy, it is returned to no-one: any reference to it is lost (and will be garbage collected).
The code following after the line with await will execute asynchronously, so after all of your push calls have already executed. That means that console.log will execute when the array already has two elements. Promises are thus not the right tool for what you want, as the resolution of a promise can only be acted upon when all other synchronous code has run to completion. To get notifications during the execution synchronously, you need a synchronous solution, while promises are based on asynchronous execution.
Just to complete the answer, I provide here a simple synchronous callback solution:
function observed(array, cb) {
return new Proxy(array, {
set(array, key, val) {
array[key] = val;
if (!isNaN(key)) cb(); // now it is synchronous
return true;
}
});
}
let a = observed([], () =>
console.log(new Date().toLocaleTimeString(),"Blimey Guv'nor:", `${a.pop()}`)
);
a.push('ʕ·͡ᴥ·ʔ');
a.push('¯\(°_o)/¯ ');
As noted before: promises are not the right tool when you need synchronous code execution.
When each push is executed asynchronously
You can use promises, if you are sure that each push happens in a separate task, where the promise job queue is processed in between every pair of push calls.
For instance, if you make each push call as part of an input event handler, or as the callback for a setTimeout timer, then it is possible:
function observed(array) {
let resolve = () => null; // dummy
let proxy = new Proxy(array, {
set(array, key, val) {
array[key] = val;
if (!isNaN(key)) resolve();
return true;
}
});
proxy.observe = () => new Promise(r => resolve = r);
return proxy;
}
let a = observed([]);
(async () => {
while (true) {
await a.observe();
console.log(new Date().toLocaleTimeString(),"Blimey Guv'nor:",`${a.pop()}`);
}
})();
setTimeout(() => a.push('ʕ·͡ᴥ·ʔ'), 100);
setTimeout(() => a.push('¯\(°_o)/¯ '), 100);

Using generators to pause until promise resolves

I have a batch job in node.js that: copies files into a directory, does analysis on files, then removes files.
I would like to iterate over an array of jobs and use generators to pause execution until that batch job is complete before starting another job. Here is what I have so far:
const cars = ["toyota", "honda", "acura"];
function copyFilesAndRunAnalysis(car) {
return new Promise(function(resolve, reject) {
setTimeout(function() { // simulate some delay
resolve(); // control should return to generator here
}, 1000);
});
}
function* doCar(car) {
yield copyFilesAndRunAnalysis(car);
}
// BEGIN HERE
console.log('start here');
carBatch = doCar(cars[0]);
carBatch.next(); // confusion here!!!
carBatch.next(); // should this all be in a forEach loop?
What I'd like to do is have a forEach that loops over each car, does all the respective work in the copyFilesAndRunAnalysis method -- pausing until Promise.resolve() and then on to the next one. Trying forEach does not make anything run at all.
You do not use .value at js at Question. The .value of the next() object yielded by Generator would be the Promise returned from copyFilesAndRunAnalysis, where .then() could be chained to .next().value(), Array.prototype.shift() could be used to recursively call doCar until no items remain within original or copy of cars array.
const cars = ["toyota", "honda", "acura"];
let carsCopy = cars.slice(0);
function copyFilesAndRunAnalysis(car) {
return new Promise(function(resolve, reject) {
setTimeout(function() { // simulate some delay
resolve(car); // control should return to generator here
}, 1000);
})
}
function* doCar(cars) {
yield copyFilesAndRunAnalysis(cars);
}
// BEGIN HERE
console.log("start here");
carBatch = doCar(carsCopy.shift());
carBatch.next().value.then(function re(data) {
console.log(data);
return carsCopy.length
? doCar(carsCopy.shift()).next().value.then(re)
: "complete"
})
.then(function(complete) {
console.log(complete);
})
Note, the same process can be achieved utilizing Promise, recursion; without using a Generator function.
const cars = ["toyota", "honda", "acura"];
let carsCopy = cars.slice(0);
function copyFilesAndRunAnalysis(car) {
return new Promise(function(resolve, reject) {
setTimeout(function() { // simulate some delay
resolve(car); // control should return to generator here
}, 1000);
})
}
// BEGIN HERE
console.log("start here");
carBatch = copyFilesAndRunAnalysis(carsCopy.shift());
carBatch.then(function re(data) {
console.log(data);
return carsCopy.length
? copyFilesAndRunAnalysis(carsCopy.shift()).then(re)
: "complete"
})
// do stuff when all items within `cars` have been
// processed through `copyFilesAndRunAnalysis`
.then(function(complete) {
console.log(complete);
})
ES6 generators don't have anything to do with asynchronous execution. They provide usable mechanism for implementing async control flow in third-party code (particularly co).
It may be used like that
co(function* () {
console.log('start here');
for (let car of cars) {
yield copyFilesAndRunAnalysis(car);
}
console.log('end here');
});
co transforms wrapped generator function into a promise and doesn't make miracles. All asynchronous actions should be performed inside generator function.

How do promises work in JavaScript?

I just implemented my first function that returns a promise based on another promise in AngularJS, and it worked. But before I decided to just do it, I spent 2 hours reading and trying to understand the concepts behind promises. I thought if I could write a simple piece of code that simulated how promises worked, I would then be able to conceptually understand it instead of being able to use it without really knowing how it works. I couldn't write that code.
So, could someone please illustrate in vanilla JavaScript how promises work?
A promise is basically an object with two methods. One method is for defining what to do, and one is for telling when to do it. It has to be possible to call the two methods in any order, so the object needs to keep track of which one has been called:
var promise = {
isDone: false,
doneHandler: null,
done: function(f) {
if (this.isDone) {
f();
} else {
this.doneHandler = f;
}
},
callDone: function() {
if (this.doneHandler != null) {
this.doneHandler();
} else {
this.isDone = true;
}
}
};
You can define the action first, then trigger it:
promise.done(function(){ alert('done'); });
promise.callDone();
You can trigger the action first, then define it:
promise.callDone();
promise.done(function(){ alert('done'); });
Demo: http://jsfiddle.net/EvN9P/
When you use a promise in an asynchronous function, the function creates the empty promise, keeps a reference to it, and also returns the reference. The code that handles the asynchronous response will trigger the action in the promise, and the code calling the asynchronous function will define the action.
As either of those can happen in any order, the code calling the asynchronous function can hang on to the promise and define the action any time it wants.
For the simplicity to understand about the promises in Javascript.
You can refer below example. Just copy paste in a new php/html file and run.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function test(n){
alert('input:'+n);
var promise = new Promise(function(fulfill, reject) {
/*put your condition here */
if(n) {
fulfill("Inside If! match found");
}
else {
reject(Error("It broke"));
}
});
promise.then(function(result) {
alert(result); // "Inside If! match found"
}, function(err) {
alert(err); // Error: "It broke"
});
}
</script>
</head>
<body>
<input type="button" onclick="test(1);" value="Test"/>
</body>
</html>
Click on Test button,
It will create new promise,
if condition will be true it fulfill the response,
after that promise.then called and based on the fulfill it will print the result.
In case of reject promise.then returns the error message.
Probably the simplest example of promises usage looks like that:
var method1 = (addings = '') => {
return new Promise(resolve => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '') => {
return new Promise(resolve => {
console.log('method2' + addings)
resolve(addings + '_adding2');
});
}
method1().then(method2).then(method1).then(method2);
// result:
// method1
// method2_adding1
// method1_adding1_adding2
// method2_adding1_adding2_adding1
That's basic of basics. Having it, you can experiment with rejects:
var method1 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method1' + addings)
resolve(addings + '_adding1');
});
}
var method2 = (addings = '*') => {
return new Promise((resolve, reject) => {
console.log('method2' + addings)
reject();
});
}
var errorMethod = () => {
console.log('errorMethod')
}
method1()
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod)
.then(method1, errorMethod)
.then(method2, errorMethod);
// result:
// method1*
// method2*_adding1
// errorMethod
// method2*
// errorMethod
// method2*
As we can see, in case of failure error function is fired (which is always the second argument of then) and then next function in chain is fired with no given argument.
For advanced knowledge I invite you here.
please check this simple promise code. this will help you to better understand of promise functionality.
A promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved. A promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.
let myPromise = new Promise((resolve, reject)=>{
if(2==2){
resolve("resolved")
}else{
reject("rejected")
}
});
myPromise.then((message)=>{
document.write(`the promise is ${message}`)
}).catch((message)=>{
document.write(`the promise is ${message}`)
})
check this out

Categories

Resources