First of all rollback is something that I do not care about.
I would like to be able to lock a sequence of async functions/promises/tasks (let's call it a "transaction") with a name/id (or array of names), so that they happen in sequence, and so that any other "transaction" with the same name(s) that are run by another part of the system are delayed from starting until the running transaction using the same name(s) has completed. So it basically is queueing the sequences of async tasks, or "transaction"s.
Here is some example code of the situation:
function a()
{
// do stuff
return new Promise(/*...*/);
}
function b()
{
// do stuff
return new Promise(/*...*/);
}
function c()
{
// do stuff
return a.then(() => b());
}
Now at any time the system could call a, b, or c, and when it does I don't want c and b running at the same time, but obvious c depends on b.
I've been looking for a package on npm to help with this but I haven't found anything, I wonder if anyone can suggest something that I might have missed that would help with this?
I think gulp tasks can help you out of the box. This guarantees that c always run after b and so b after a
const gulp = require('gulp');
gulp.task('a', done => {
// do stuff
console.log('a');
done();
});
gulp.task('b', ['a'], done => {
// do stuff
console.log('b');
done();
});
gulp.task('c', ['b'], done => {
// do more stuff
console.log('c');
done();
});
gulp.start('c'); // Logs a, b, c
Try it!
You could write your own little transaction manager.
const transactions = {};
function doTransaction(name, promiseFunc) {
transactions[name] = (transactions[name] || Promise.resolve()).then(promiseFunc);
}
Use async/await and have babel transpile it. Async Babel Docs
function a()
{
// do stuff
return new Promise(/*...*/);
}
async function b()
{
const aData = await a();
// do stuff
return new Promise(/*...*/);
}
async function c()
{
const bData = await b();
// do stuff
return bData;
}
You can go for https://github.com/Reactive-Extensions/RxJS
They have many functions to handle single/multiple/dependent/parallel async calls.
function a()
{
// do stuff
return new Promise(/*...*/);
}
function b()
{
// do stuff
return new Promise(/*...*/);
}
function c()
{
// do stuff
return new Value;
}
a().then(function(data_a) {
// you can make use of return value (which is data_a) here or as an argument for function b or even function c
b().then(function(data_b) {
// you can make use of return value (which is data_b) here or as an argument for function c
c().then(function(data_c) {
// do your coding here
});
});
});
you can check this link for reference : https://spring.io/understanding/javascript-promises
Ok, here's my take.
You use a wrapper for your function b which returns and object with 2 methods: doCall and wait. The wrapper should be called only once.
doCall will call your function and trace its completion for the wait() function.
wait() will wait for the completion and always resolve when doCall() finishes
Now for the code, also on CodePen (see developer console):
function wrapPromiseFn(fn) {
var prev = null;
var doCall = function() {
var retValue;
prev = new Promise(function(resolve, reject) {
retValue = fn();
retValue.then(function(result) {
resolve(true);
});
retValue.catch(function(result) {
resolve(true);
});
});
return retValue;
};
var wait = function() {
return prev ? prev : Promise.resolve(false);
};
return {
doCall: doCall,
wait: wait
};
}
function a() {
return Promise.resolve(42);
}
function b() {
//return Promise.reject(new Date());
return Promise.resolve(new Date().getTime());
}
var wrappedB = wrapPromiseFn(b);
function doStuff() {
return wrappedB.wait().then(function(didWait) {
return a().then(function(_a) {
return wrappedB.doCall().then(function(_b) {
console.log("didWait, a, b: ", didWait, _a, _b);
});
});
});
}
//run it twice to prove it did wait
doStuff().then(doStuff)
It proves the concept, of course it would need some polish to pass arguments from doCall to the wrapped function.
Related
I have a function (f1) which I want to get called only after two ajax calls (say a1 and a2) are done. a2 should be called only after a1 is done. Following is the sequence of operation =
$.when(a1 and a2) {
f1
}
I tried the following code snippet -
$.when(a1a2()).done(function(){
f1();
}
var a1a2 = function(){
return $.when(a1()).done(function() {
if (<check for a few variables a1 sets>) {
// another ajax call for which f1 should wait
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
});
}
In the above code, f1 is waiting for a1 to finish but it is not waiting for a2 to finish.
I tried the following code snippet as well (but this also just waits for a1 to finish) -
var a1a2 = function(){
var retVal = new Promise(function(){
a1().then(function(){
if (<check for a few variables a1 sets>) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
});
});
}
I have looked at other similar questions but an not able to devise a solution. Can someone please help?
First of all, your Promise code is faulty, because you're not creating a Promise correctly
new Promise(function(resolve, reject) {
// in here you call resolve or reject otherwise Promise is forever pending
});
However, since a1 returns a Promise (as do all the functions, I'm assuming) you don't need to create a promise
So, your code would be
a1()
.then(function() {
if (somecondition == true) {
return a2();
} else {
f2(); // since there's no return here, there's no "wait" for the promise f2 returns
}
})
.then(function() {
return f1();
})
To illustrate the above, here's your code once with condition true, and then with condition false
Take note of the "time stamps" for the console output
// dummy code to set up some promises
const dummy = (x, d=1000) => {
console.log(performance.now(), 'start', x);
return new Promise(resolve => setTimeout(() => {
console.log(performance.now(), 'end', x);
resolve(x);
}, d));
};
const a1 = () => dummy('a1');
const a2 = () => dummy('a2');
const f1 = () => dummy('f1');
const f2 = () => dummy('f2', 3000);
// end dummy code
console.log('wait for a2');
a1()
.then(function() {
if (true) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
})
.then(function() {
return f1();
})
.then(() => {
console.log('dont wait for f2');
a1()
.then(function() {
if (false) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
})
.then(function() {
f1();
});
});
However! If f2 is a function that has no asynchrony then there is no way * to prevent f1 from being called after f2 finish - because that's how javascript works
* - I guess you could put it in a setTimeout, then f2 would execute after f1 begins (again, assuming f1 has some asynchrony, otherwise f2 would begin after f1 ends)
Call a1 to get its Promise, then call Promise.all on a1 and a1 chained with a2:
const a1Prom = a1();
Promise.all([
a1Prom,
a1Prom.then(a2)
])
.then(f1);
console.log('script start');
const delay = ms => new Promise(res => setTimeout(res, ms));
const a1 = () => delay(1000).then(() => console.log('a1 done'));
const a2 = () => {
console.log('a2 starting');
return delay(1000).then(() => console.log('a2 done'));
};
const f1 = () => console.log('f1 starting');
const a1Prom = a1();
Promise.all([
a1Prom,
a1Prom.then(a2)
])
.then(f1);
I'm not familiar with the when/done syntax, but this is a correction for your second snippet. A big hint I would give is that using new Promise is 90% of the time a bad idea.
var a1a2 = function(){
var retVal = a1().then(function(){
if (<check for a few variables a1 sets>) {
return a2();
} else {
// random function for which f1 shouldn't wait
f2();
}
});
});
function a1() {
return new Promise(resolve => {
resolve();
});
}
function a2() {
return new Promise(resolve => {
resolve();
});
}
function f1() {
// this runs when the a1 and a2 is resolved.
}
// this is the call method. there are so many approach in your question first is chaining of promise.
function CallMethod(){
a1().then(function () { // you can optionally pass data here via the resolve in the promise
return a2();
}).then(function () { // same here you can pass optional data here.
// here the a1 and a2 is resolved you can call the f1() now.
f1();
});
}
// second one is called Promise.all()
function CallMethod() {
Promise.all([a1(), a2()]).then(data => { // this is the optional data passed in the resolve base on the index of the function promises.
var firstResolve = data[0]; // resolved data of a1();
var secondResolve = data[1]; // resolved data of a2();
})
}
I have written long code, trying to replicate the situation in simple form by this simple code.
What I want to do is after function A() completion, call function B().
I am trying with callback function but in this case, B fired early.
Please suggest how can I write this callback or any other approach?
function A(callback){
a()
function a() {
setTimeout(aa,1000)
function aa(){
console.log("in aa")
}
}
b()
function b() {
setTimeout(bb,100)
function bb(){
console.log("in bb")
}
}
c()
function c(){
setTimeout(cc,50)
function cc(){
console.log("in cc")
}
}
callback();
}
function B() {
console.log("in B");
}
A(B)
output
in B
in cc
in bb
in aa
If you want your callback to run after a timeout has finished, then you have to call it when the timeout has finished.
And that means it needs to be at the end of the function you pass to setTimeout.
With your current code, you are setting the countdown on the timeout going and then immediately calling the callback.
function one(callback) {
console.log(1);
function two() {
console.log(2);
callback();
}
setTimeout(two, 250);
}
function three() {
console.log(3);
}
one(three);
Essentially, what's happening here (as you requested) is that you want B to run after A is completed.
There is no need to use "B" as a callback, with async/await.
B will wait till A is completed before it's called.
const b = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{resolve("B done")}, 1000);
});
}
const c = () => {
return new Promise((resolve, reject)=>{
setTimeout(()=>{resolve("C done")}, 500);
});
}
const A = async () => {
const bres = await b();
console.log(bres);
const cres = await c();
console.log(cres);
};
const B = async () => {
console.log("done");
}
const app = async() => {
await A();
await B();
};
app();
I want to call two function say function a() and function b() in parallel. These functions are independent to each other, and lets say the time required to execute these two functions are not fixed. Sometimes function a() will take more time than function b() and vice versa. But there is another function c() that should only execute when both the functions a() and b() are completed.
How should I do this using jQuery's Deferred object?
To achieve this you can make the a() and b() functions return deferred objects which you resolve() once their logic has completed. You can then run c() once both previous functions have completed. Try this:
function a() {
var aDef = $.Deferred();
setTimeout(function() {
aDef.resolve('a done');
}, 1000);
return aDef;
}
function b() {
var bDef = $.Deferred();
setTimeout(function() {
bDef.resolve('b done');
}, 3000);
return bDef;
}
function c() {
console.log('all done!')
}
console.log('running...');
$.when(a(), b()).done(function(a, b) {
console.log(a);
console.log(b);
c();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'd use a global variable to determ an operational status and execute a polling each 100 milliseconds (or each milliseconds if you need).
var myStatus = {
"a": false,
"b": false
};
function a() {
myStatus["a"] = true;
console.log(myStatus['a']);
}
function b() {
myStatus["b"] = true;
}
function getStatusText() {
var s = 'not complete';
if (myStatus.a && myStatus.b) {
s = 'all complete';
} else {
if (myStatus.a) {
s = 'a complete';
}
if (myStatus.b) {
s = 'b complete';
}
}
return s;
}
function c() {
//check operational status
var statusText = getStatusText();
document.getElementById('status').innerHTML = statusText;
}
setInterval(
function() {
c()
}, 100);
<button onclick="a()">Set a() complete</button><button onclick="b()">Set b() complete</button>
<p>operational status <span id="status"></span></p>
Please refer Jquery defer and promise method to handle calls.
https://api.jquery.com/deferred.promise/ or
https://api.jquery.com/promise/
This is not exactly an answer to the question. I don't use defer or anything like it.
But I want to show something I do quite often: add a onReady callback, as a parameter to a() and b(). I add these callbacks to any self-written-function that takes time to execute.
function a(onready) {
// let's say we get Ajax data
$.ajax({
url: 'data.php',
success: function(data) {
$('#message').html(data);
if(typeof onready == 'function') {
onready(); // you might also want to add message as a parameter, like onready(data), or anready('Data okay'), ...
}
}
});
}
function b(onready) {
// let's say we sort <table> rows
sortTable('my_table', 'my_row', 'ASC'); // this function (not provided here) is not asynchronous, it just takes time before it's done
if(typeof onready == 'function') {
onready();
}
}
function c() {
alert('Yippy!');
}
$(document).ready(function() { // or this could be after the client clicks on a button, or so
var aReady = false;
var bReady = false;
a(function() {
aReady = true;
if(aReady && bReady) {
c();
}
});
b(function() {
bReady = true;
if(aReady && bReady) {
c();
}
});
});
You can use jQuery.when() to do this. Please read the document about this at https://api.jquery.com/jquery.when/
a = function () {
//your code for function a
}
b = function () {
//your code for function b
}
$.when( a(), b() ).done(function c() {
//your code for function c
});
I want to create a chain of asynchronous methods in Node.js, for example:
function functionA(data, callback){
console.log("A")
// do something here
callback();
}
function functionB(data, callback){
console.log("B");
// do something here
callback();
}
function functionC(data, callback){
console.log("C");
// do something here
callback();
}
each function is independent, but when chained, they can be called orderly. For example:
functionA(data).functionC(data).functionB(data)
will print A then C then B. The chain's order can be re-arranged without restriction.
Here's what I have been searched:
Create chained methods in node.js?, --> here's the previous question regarding this very topic, very old, also not async
http://www.dustindiaz.com/async-method-queues/ --> depends on jquery, client side script, not node, not async
https://github.com/FuturesJS/FuturesJS/tree/v3 --> deprecated, the newer version (3) with chainify feature unfinished. Looks like an abandoned project
I use async a lot, I know about waterfall, series, and many functions that I use regularly, I just want to re-arrange it to something simpler to use in multiple places. I think about how to "chaining" them, so that in other file I can use the same method.
Here's my reason why async is not the answer that I expect.
Consider accounting problem, if there's a sell transaction with total $1200, first I had to put $1200 into asset:cash book(debit side), then I had to put $1200 into income book(credit side). Is it do-able with async? yes of course. it'll look like this:
async.series([
function(callback){
bookLibrary.debit('cash', 1200, callback);
},
function(callback){
bookLibrary.credit('income', 1200, callback);
}
]);
so I want to make it much simpler and easier to read by chaining them, like this:
bookLibrary.debit('cash', 1200).credit('income', 1200)
First off, to chain a bunch of functions, you need them to be configured as methods on a common object. Then, each method can return that object so the return result is the object and the next method can be called on that object.
So, to do something like this:
a().b().c();
You need a() to return an object that has the method b() on it as a property. And, similarly you need a().b() to return an object that has c() on it as a property. This is generally called the Fluent Interface. That's all pretty straightforward by itself for synchronous methods. This is exactly how jQuery does its chaining.
$(".foo").show().css("color", "blue");
All three of these calls all return a jQuery object and that jQuery object contains all the methods that you can chain.
In the example above, you could do synchronous chaining like this:
function a() {
}
a.prototype = {
b: function() {
// do something
return this;
},
c: function() {
// do something else
return this;
}
};
But, your question is about asynchronous operations. That is significantly more work because when you do:
a().b().c();
That's going to execute all three methods immediately one after the other and will not wait for any of them to complete. With this exact syntax, the only way I know of to support chaining is to build a queue where instead of actually executing .b(xxx) right away, the object queues that operation until a() finishes. This is how jQuery does animations as in:
$(".foo").slideUp().slideDown();
So, the object that is returned from each method can contain a queue and when one operation completes, the object then pulls the next item from the queue, assigns it's arguments (that are also held in the queue), executes it and monitors for that async operation to be done where it again pulls the next item from the queue.
Here's a general idea for a queue. As I got into this implementation, I realized that promises would make this a lot easier. Here's the general idea for an implementation that doesn't use promises (untested):
For simplicity of example for async operations, lets make a() execute a 10ms setTimeout, .b() a 50ms setTimeout and .c() a 100ms setTimeout. In practice, these could be any async operations that call a callback when done.
function a() {
if (!(this instanceof a)) {
return new a();
} else {
this.queue = [];
this.inProgress = false;
this.add(function(callback) {
// here our sample 10ms async operation
setTimeout(function() {
callback(null);
}, 10);
}, arguments);
}
}
a.prototype = {
b: function() {
this.add(function(callback) {
// here our sample 50ms async operation
setTimeout(function() {
callback(null);
}, 50);
return this;
}, arguments);
},
c: function(t) {
this.add(function(t, callback) {
// here our sample 100ms async operation
setTimeout(function() {
callback(null);
}, t);
return this;
}, arguments);
},
add: function(fn, args) {
// make copy of args
var savedArgs = Array.prototype.slice.call(args);
this.queue.push({fn: fn, args:savedArgs});
this._next();
},
_next: function() {
// execute the next item in the queue if one not already running
var item;
if (!this.inProgress && this.queue.length) {
this.inProgress = true;
item = this.queue.shift();
// add custom callback to end of args
item.args.push(function(err) {
this.inProgress = false;
if (err) {
// clear queue and stop execution on an error
this.queue = [];
} else {
// otherwise go to next queued operation
this._next();
}
});
try {
item.fn.apply(this, item.args);
} catch(e) {
// stop on error
this.queue = [];
this.inProgress = false;
}
}
}
};
// usage
a().b().c(100);
If we use promises for both our async operations and for the queuing, then things get a bit simpler:
All async operations such as firstAsyncOperation and secondAsyncOperation here return a promise which drastically simplifies things. The async chaining is done for us by the promise infrastructure.
function a(arg1, arg2) {
if (!(this instanceof a)) {
return new a(arg1, arg2);
} else {
this.p = firstAsyncOperation(arg1, arg2);
}
}
a.prototype = {
b: function() {
return this._chain(secondAsyncOperation, arguments);
},
c: function() {
return this._chain(thirdAsyncOperation, arguments);
},
_chain: function(fn, args) {
var savedArgs = Array.prototype.slice.call(args);
this.p = this.p.then(function() {
return fn.apply(this, savedArgs);
});
return this;
},
then: function(a, b) {
this.p = this.p.then(a, b);
return this;
},
catch: function(fn) {
this.p = this.p.catch(fn);
return this;
}
};
// usage:
a().b().c(100).then(function() {
// done here
}).catch(function() {
// error here
});
You can use async waterfall to do that, this should meet your requirement.
async.waterfall([
function(callback) {
callback(null, 'one', 'two');
},
function(arg1, arg2, callback) {
// arg1 now equals 'one' and arg2 now equals 'two'
callback(null, 'three');
},
function(arg1, callback) {
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});
You can do this by having all your functions enclosed in a single object , just like below.
var Ext = {
function a() {
return this;
}
function b() {
return this;
}
}
then you can call them as below
Ext.a().b();
for detailed example please look at the code of my javascript library which does exactly what you need https://github.com/waqaskhan540/MapperJs
I have a question about promises.
I am using Bluebird Promise library and build a small async library with it.
I am trying to waterfall promises with the use of a function.
Say I use promises like so:
Promise.resolve()
.then(function () {
console.log("called 1")
return 1;
}).then(function () {
return new Promise (function (res, rej) {
setTimeout(function () {
console.log("called 2")
res(2);
}, 1500);
});
}).then(function () {
console.log("called 3")
return 3;
});
This does in fact wait in a loop and return 1,2,3 in order.
How do I wrap it into a function so that I can do something like this:
a();b();c();, or a().b().c(); where a() puts something onto a chain, b() puts something onto a chain, and c() puts something onto a chain in order.
Since then() returns a new promise, it can all go out of order, so something like
does not work:
var promise = Promise.resolve();
function a () {
promise.then(function () {
// do sync/async
});
}
function b () {
promise.then(function () {
//do sync/async
});
}
function c ...
Thank you for your time :]
I'm not sure what the goal is here. Do you want to have an arbitrary number of things run in sequence where the sequence is known in advance? Or is this a case where the sequence is discovered as you go? The NodeJS streams interface is a lot better for processing an unknown number of things sequentially (#tadman)
Sequence is discoverable, goal is to have ability to call a().b().c() or b().a().d(). Async library on a client-side.
Update: If I do as #zerkms says it does not work as expected. My bad, should work ok, but with lack of context/code did not give me enough info to expand on. Still thank you for your answer, as it gave me more food for thought.
Update: See my answer
You could use a scoped prototype and just add those methods there
Promise.prototype.a = function() {
return this.then(function() {
console.log("called 1")
return 1;
});
};
Promise.prototype.b = function() {
return this.delay(1500).then(function() {
console.log("called 2")
return 1;
});
};
Promise.prototype.c = function() {
return this.then(function() {
console.log("called 3")
return 3;
});
};
I use this to create neat DSLs e.g. with git:
https://gist.github.com/petkaantonov/6a73bd1a35d471ddc586
Thanks to #tadman I came up with this so far, seems to work as I expect it to.
The problem was that I did not update the promise before calling then on it, and it was branching instead of calling it in sequence.
And this is what I wanted - to turn an object that has both sync/async into async to allow chaining. Petka (#Esailija) also shows great example of building DSLs above (semvar version bumping & git pushing) by extending bluebird library, but for my purposes this is enough.
var Sample = function () {
this.promise = Promise.resolve();
};
Sample.prototype.a = function () {
this.then(function () {
console.log("1");
});
return this;
};
Sample.prototype.b = function () {
this.then(function () {
return new Promise(function (res, rej) {
setTimeout(function() {
console.log("2");
res();
}, 500);
});
});
return this;
};
Sample.prototype.c = function () {
this.then(function () {
console.log("3");
})
return this;
};
Sample.prototype.chainPromise = function (func) {
this.promise = this.promise.then(func);
};
var s = new Sample();
s.a().b().c();
or even then instead of chainPromise?
Sample.prototype.then = function (func) {
this.promise = this.promise.then(func);
return this.promise;
};