willconant / flow-js Goto Github PK
View Code? Open in Web Editor NEWJavascript Library for Multi-step Asynchronous Logic
License: MIT License
Javascript Library for Multi-step Asynchronous Logic
License: MIT License
I'm trying to avoid async callback hell by creating a flow for a more complex set of API calls. Currently I have something like this:
//var lookupSQL can't go here
flow.exec(
function(){
// see if user is in lookup table
var lookupSQL = "SELECT * FROM ?? WHERE slackUserID = ?";
pool.query(lookupSQL, [usersLUTable, message.user], this.MULTI("lookup_user"));
// need to pass these on, or they won't be visible in the next function() call
this.MULTI("params")(bot, message, callback, pool, this);
},function(results){
var bot = results.params[0],
message = results.params[1],
callback = results.params[2];
if(results.lookup_user[0]){
// error in SQL query
}
var results = results.lookup_user[1];
var isKnownUser = false;
if(results.length == 0){
//
}else{
isKnownUser = true;
}
bot.api.users.info({user: message.user}, this.MULTI("userInfo"));
// pass the same info to the next sync function
this.MULTI("params")(bot, message, callback, isKnownUser);
},function(results){
var bot = results.params[0],
message = results.params[1],
callback = results.params[2],
isKnownUser = results.params[3],
userInfo = results.userInfo;
}
);
I've noticed that I can't seem to maintain access to many both local and global variables & functions during each callback. For example, the global params in the first function() of the flow work as I want them to:
However, in the next callback these will return "undefined", so I have to maintain them by manually adding & storing them through a custom this.MULTI("params") call. I have to do this in each step of the flow. Is this really the right way of doing this, or have I missed something obvious? It doesn't seem right to manually maintain that each step.
Thanks
When issuing multiple parallel requests and this.MULTI(), one can get the request results with argsArray.
However, I need to pass some additional data, besides the data returned by the callbacks. Something like
fs.rename("/tmp/c", "/tmp/3", this.MULTI(myData));
or
fs.rename("/tmp/c", "/tmp/3", this.MULTI(), myData );
I'll use myData in the final function to figure out at what result I'm looking at.
Is any kind of conditional flow control available? E.g. in step 3, if A, then go to step 5, else if B then go to step 7, otherwise go on with step 4.
Not sure if you are interested in supporting these browsers (I am !) Great little library you have here.
In my code below, the second function in the flow gets called before both callbacks when on IE, but in Chrome, the iPad, etc it works fine.
// in parallel start the transition and the XHR
var count = 0;
flow.exec(
function() {
// Start the CSS transition to hide
var transMulti = this.MULTI();
$control.parent().addClassTrans('removed', function() { count++; transMulti(); });
// In parallel, tell the server to hide facets
var xhrMulti = this.MULTI();
x$(document).xhr(url, {
data: 'facet=' + facetName,
async: true,
method: 'post',
callback: function() { count++; xhrMulti(); }
});
},
function() {
if (count != 2)
alert('fucked: ' + count);
// if we're selected, then hide our value pane
if (selected)
hideValues();
// actually remove it, now that its hidden
$control.parent().remove();
// fetch new facets
updateSuggested();
}
);
Would be helpful to users considering this library to have readily-available browser support information.
Examples:
We're using Backbone models and collections in combination with flow-js to sync API calls. As per your example, MULTI()
takes a parameter that allows it to identify a result when multiple async methods are required to complete before continuing. However:
flow.exec(
->
aCb = @MULTI 'a'
bCb = @MULTI 'b'
aModel.fetch success: aCb, error: aCb
bModel.fetch success: bCb, error: bCb
(results) ->
console.debug results # => [Array[2], Array[2]]
)
The code returns a numerically indexed array instead, so your example of results['a']
and results['b']
return undefined
.
I have Require.JS in my JS folder, along side Flow.JS.
I have added the script tag to load Require.JS, then in another script, called:
var flow = require('./flow');
As per the Readme, but it doesn't work.
I get:
Uncaught Error: Module name "flow" has not been loaded yet for context: _. Use require([])
http://requirejs.org/docs/errors.html#notloaded
require.js:8 Uncaught Error: Mismatched anonymous define() module: function (){return c}
http://requirejs.org/docs/errors.html#mismatch
I then tried:
var flow = require(['./flow']);
But I got:
Uncaught Error: Mismatched anonymous define() module: function (){return c}
http://requirejs.org/docs/errors.html#mismatch
Can I get some help on installing this? Ideally without Require.JS, as I am not using it (apart form to try and load this library!)
Thank you for the great library.
The only problem there: On npm repository in package.json you have version = 0.2.2, but actually it's not.
Please check number of lines inside flow.js and test.js files (may be others).
I think version number was updated, but there are old sources in repository!
Thanks!
I really like the way the code for flow-js looks, but I am having trouble wrapping my head around how I could call an async method that takes two callback methods. One for success and one for failure.
Example method:
myRequest: function(successCb, failureCb) { ... }
I would need a flow that chooses the next method to hit in the flow based upon the success or failure. Something like:
flow.exec(
function() { // step 1
myRequest(this.FN1(), this.FN2())
},function(successParams) { // step 2
// do something
},function(errParams) { // step 1 error
if (err) throw err;
},function(param) { // step 3
// do something more
}
);
So on success the flow would be: step1, step2, step3.
On failure it would be: step1, step1 error, throw.
Is this possible?
You could modify this slightly to work with node's async interface where the first parameter to the callback is the error message. Then it would work with all the built-in node async functions out of the box.
Hello,
I'm trying to put together a more complex serialForEach example, which includes "jumping" manually to next step, based on the example in issue #3.
step 1: search for the value
step 2: if found, just go to next step. If not, search again using different parameters, and go to next step using that value
flow.serialForEach(["refe", "lkajdflkjwernm", "crypto", "poidfgmnermn"], function(val) {
console.log("Searching for " + val)
$.ajax({
type: "GET",
url: 'https://api.stackexchange.com/2.1/badges?key=U4DMV*8nvpm3EOpvf69Rxw((&site=stackoverflow&order=desc&sort=rank&filter=default',
data: {inname: val},
success: this
})
},function(search_result) {
console.log('search_result')
console.log(search_result)
var next = this
if (search_result.items.length > 0) {
console.log('found')
next(search_result.items[0])
} else {
console.log('NOT found')
//just get the latest badge
$.ajax({
type: "GET",
url: 'https://api.stackexchange.com/2.1/badges?key=U4DMV*8nvpm3EOpvf69Rxw((&site=stackoverflow&order=desc&sort=rank&filter=default',
data: {},
success: this
})
}
},function(badge) {
console.log('badge')
console.log(badge)
},function() {
console.log('This is the end!');
});
There are multiple issues with this sample:
How should the code look for this to work?
Thanks
Hello,
Can flow-js also be used with promises? If so, how? I've tried leveraging this.MULTI() but the next function never fires:
const flow = require('flow');
function generateRandomNumber () {
return new Promise(function (resolve, reject) {
var randomNumber = Math.floor((Math.random() * 10) + 1)
if (randomNumber <= 5) {
resolve(randomNumber)
} else {
reject(randomNumber)
}
})
}
/*
generateRandomNumber().then(function(result) {
console.log('Success: ' + result)
}).catch(function(error) {
console.log('Error: ' + error)
})//*/
flow.exec(
function(){
generateRandomNumber().then(this.MULTI("RES1")).catch(this.MULTI("REJ1"));
generateRandomNumber().then(this.MULTI("RES2")).catch(this.MULTI("REJ2"));
},function(argsArray){
debugger;
console.log("this is the data: ",JSON.stringify(argsArray));
}
);
console.log("EOF");
It works really well for function() callbacks, though I'd love to also leverage this for promises if possible.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.