How can I make this work
var asyncToSync = syncFunc();
function syncFunc() {
var sync = true;
var data = null;
query(params, function(result){
data = result;
sync = false;
});
while(sync) {}
return data;
}
I tried to get sync function from async one,
I need it to use FreeTds async query as sync one
Use deasync - a module written in C++ which exposes Node.js event loop to JavaScript. The module also exposes a sleep function that blocks subsequent code but doesn't block entire thread, nor incur busy wait. You can put the sleep function in your while loop:
var asyncToSync = syncFunc();
function syncFunc() {
var sync = true;
var data = null;
query(params, function(result){
data = result;
sync = false;
});
while(sync) {require('deasync').sleep(100);}
return data;
}
Nowadays this generator pattern can be a fantastic solution in many situations:
// nodejs script doing sequential prompts using async readline.question function
var main = (function* () {
// just import and initialize 'readline' in nodejs
var r = require('readline')
var rl = r.createInterface({input: process.stdin, output: process.stdout })
// magic here, the callback is the iterator.next
var answerA = yield rl.question('do you want this? ', res=>main.next(res))
// and again, in a sync fashion
var answerB = yield rl.question('are you sure? ', res=>main.next(res))
// readline boilerplate
rl.close()
console.log(answerA, answerB)
})() // <-- executed: iterator created from generator
main.next() // kick off the iterator,
// runs until the first 'yield', including rightmost code
// and waits until another main.next() happens
You can do it with node-sync lib
var sync = require('sync');
sync(function(){
var result = query.sync(query, params);
// result can be used immediately
})
Notice: your query must use standart callback call (with error first): callback(error, result).
If you can't change query method, just create .async() wrapper (see github link).
I've been using syncrhonize.js with great success. There's even a pending pull request (which works quite well) to support async functions which have multiple parameters. Far better and easier to use than node-sync imho. Added bonus that it has easy-to-understand and thorough documentation, whereas node-sync does not.
The issue you are having is that your tight while loop is blocking. So I don't think your query callback will ever be run. I think you need to use setTimeout or the like to prevent the function from blocking, but should you do so, the function will return before the callback is called. This functionality must be implemented at a lower level.
If you are in the browser, you might check out this article. In node you have to rely on the implementation of whatever you're querying. It may or may not provide synchronous methods.
Related
I am trying to synchronously invoke a regular call-back style function in koa using generators. The following approach works:
var res = yield function (cb) {
myDaoObject.load(function (err, res) {
cb(err, res);
})
};
So I wont to replace it with the proper library use which should be equivalent:
var ld = thunkify(myDaoObject.load);
var res = yield ld();
And that doesn't work. Aren't these supposed to be the same thing?
Actually you hardly need to use thunkify here, as your function doesn't take an argument. You can (and should) however simplify it to
yield function(cb) { myDaoObject.load(cb); }
and possibly even further to just
yield myDaoObject.load;
which would work if load was not a method that used this. You will have to bind it to the object you want it get called upon:
yield myDaoObject.load.bind(myDaoObject);
The same problem was with your thunkify call - which was otherwise fine (albeit unnecessary).
I'm writing a Service Wrapper in AngularJS for Odoo Server, which has all the methods that the server supports and return a deferred promise when the service is call. E.g.:
$scope.runRPC = function(){
odooSvc.fields_get('res.users').then(
function(result){
console.log(result); //return a list of users
}
);
}
However, I need it to be synchronous, and here a reason why.
In Odoo, it has its own JSON rpc API, which has several methods that depend on each other.
For example,
search_read: give u a list of everything on the model u query on
fields_get: give u the list of fields the model has
and much more.
Usually in a working application, we need to call 2 or more API methods to get the final data we want. However, because in Java, everything works asynchronously.The code I image would be nesty and complicated.
So when I make each API calls the depends on one another. it would look like this:
$scope.setLoginToContactEmail = function(){
odooSvc.search_read('res.users').then(
function(users){
for(var i=0; i < user.length; i++){
user = users[0];
login = user.login
partner_id = user.partner_id
odooSvc.read_model('res.partner', partner_id).then(
function(partner){
if(login === partner.email){
odooSvc.write_model('res.partner', partner_id, {email: login}).then(function(msg){
console.log(msg);
});
}
}
)
}
}
);
}
Vs if I could get those API run synchronously or awaits for the data to arrived before I proceed on another call. it would look more simple:
$scope.setLoginToContactEmail = function(){
var users = odooSvc.search_read('res.users');
for(var i=0; i < user.length; i++){
user = users[0];
login = user.login
partner_id = user.partner_id
partner = odooSvc.read_model('res.partner', partner_id);
if (login === partner.email){
odooSvc.write_model('res.partner', partner_id, {email: login});
}
}
}
Please advise. Thanks.
Here is a plunker that takes care for Babel transpilation:
<body ng-app="app" ng-controller="AsyncController">
<p>{{ message }}</p>
</body>
angular.module('app', []).controller('AsyncController', ['$timeout', '$scope', async function ($timeout, $scope) {
$scope.message = 'no timeout';
$scope.message = await $timeout(() => 'timeout', 2000);
$scope.$apply();
}]);
async...await is as simple as that in TypeScript and ES.next. Two things here should be noticed.
The first one is this context inside async controller - it may differ from what is expected. This may not be a problem when classes are used and async methods are bound if necessary. This is a problem for non-OOP code when constructor function is async and cannot reach its this right from the start.
Another one is that async...await is powered by native Promises. This means that $scope.$apply() should be called to trigger digest cycles, despite the fact that digest-friendly $timeout has been used.
Async is better than sync.
However, callbacks can become very messy, so we have promises. However, promises can also become messy, although not quite as bad. Async-await is the best way to get sync-looking async code, but you have to transpile. It depends how much tooling you want to use.
Here is how I would write your ES5 code (without starting a new line after .then(, which reduces the indents a bit, and I also made some changes in the for loop as I wasn't sure what you meant):
$scope.setLoginToContactEmail = function () {
odooSvc.search_read('res.users').then(function (users) {
for (var i = 0; i < users.length; i++) {
var user = users[i]
var login = user.login
var partner_id = user.partner_id
odooSvc.read_model('res.partner', partner_id).then(function (partner) {
if (login === partner.email) {
odooSvc.write_model('res.partner', partner_id, { email: login }).then(function (msg) {
console.log(msg)
})
}
})
}
})
}
With ES6 and the proposal for async functions that can become:
$scope.setLoginToContactEmail = async function () {
const users = await odooSvc.search_read('res.users')
for (let user of users) {
const { login, partner_id } = user
const partner = await odooSvc.read_model('res.partner', partner_id)
if (login === partner.email) {
const msg = await odooSvc.write_model('res.partner', partner_id, { email: login })
console.log(msg)
}
}
}
It depends on how much transpiling you want to do. Personally, I would adopt part of ES6 (let/const, destructuring, arrow functions, template strings, modules, unicode improvements, spread operator / rest parameters, improved object literals, and possibly class literals), the stuff that you use most frequently / isn't too difficult to transpile. Maybe also use async-await: it's not a part of ES6 or ES2016, but it is at stage 3 now so it is pretty stable, and it does make async code a lot easier to read. The caveat is that you have to transpile new ES6/ES2016/etc. features using Babel or TypeScript, and use a polyfill for promises (which async-await uses internally).
TL;DR: if you find yourself descending into async hell, the async-await proposal is probably the best solution.
Asynchronous methods are the power of JavaScript which we must be utilized. And the reason is, if the task will take so long time to execute then we do not have to wait and meanwhile can put other task in execution.
We can see its advantage over the UI where we can put long taking time task in the callback and can avoid to UI be grayout.
So I would suggest to adopt aync approach.
But the way you are deciding the execution of the methods is not the better way in Angular way.
Angular has provided you $q.when(method()).then(successCallback(response));, through it control would come in successCallback only when method() execution is done and method() response can be used to make another promise call. This approach would help you to reduce the complexity of the code because you tried to make the chain of callbacks which is not correct conventionally.
$scope.setLoginToContactEmail = function(){
$q.when(searchRead()).then(function(res) {
modelRead(res);
});
}
function searchRead() {
odooSvc.search_read('res.users').then(
// #TODO
}
);
}
function modelRead(res) {
odooSvc.read_model('res.partner').then(
// #TODO
)
}
I'm looking to see if there is a way of taking a generic async function, such as AJAX, or web worker on message, and forcing it to behave synchronously.
First off - I really do need this behaviour, I am aware of all the arguments regarding async callbacks vs returns - but in this case, I truly need to wait for a callback.
If there is no generic solution available I'd settle for one that works purely on the Worker.prototype.onmessage as that is the primary use case here.
I'm fairly sure the answer will be "thats not possible" but I wanted to check before surrendering.
I've already looked into promises and generators, I'd prefer not to use a third party library (I'm aware of fiber/futures for Node).
A potential use case:
function main(){
worker = new Worker("someWorker.js")
var result = worker.onmessage(function(event){
return event.data;
})
//wait for worker.onmessage
return result;
}
If you want to preserve synchronous flow of function, the generator function is the only possible solution. You'll send out all async tasks like var result = yield new Worker('someWorker.js').
Outside the function* main you'll get the worker with mainFn.next().value and then you attach onmessage listener which will return resolved data into function* main and the function will be resumed.
The complete generator example looks like this
// write function as generator
function* main () {
var result = yield new Worker("someWorker.js");
return result;
}
// instantiate the generator and get the first yield value
var mainFn = main()
, worker = mainFn.next().value
// set onmessage listener, which is callback, that sends data back to *main()
worker.onmessage = function(event) {
mainFn.next(event.data);
}
This way your main() function will remain almost similar to original form, so you can reuse the original code, but you need to write surrounding logic, which wouldn't be simple and which would use callbacks anyway.
You seem to be aware what generators are and that it's not widely supported in the browsers wild, so if you want run this code on web page, you'll need ES6 transpiler Babel.
I have a function that pulls out from database a random question from Questions collection.
Game_Questions.js - console.log below prints out correct value (string I need), so I thought that return will let yield give me back same value.
exports.random_Question = function *() {
yield Questions.findRandom().limit(1).exec(function(err,question){
console.log("rand q: " + question[0].text);
return question[0].text;
});
}
Game.js:
var Game_Questions = require('./backend/Game_Questions');
And here I want to access question[0].text value from random_Question function from code snippet above (Game_Questions.js). What I've tried so far:
var found_Question = Game_Questions.random_Question();
var found_Question = Game_Questions.random_Question().next().value;
Those two return [Object object] which after using JSON.stringify() shows that the object is:
{"value":{"emitter":{"domain":null,"_events":{}},"emitted":{},"ended":true},"done":false}
I also tried using co(function*()) but it also didn't let me take out the value. Please help how to access it?
The answer by #remus is a callback approach and Koa was designed explicitly to ditch callbacks. So while it's perfectly good code and would fit an Express application it is completely at odds with the design philosophy behind Koa.
From the looks of it you are using Mongoose which has supported promises for async operations since version 4.0 (which was released Apr 2015) which should allow a yield approach to be taken. Note I'm making an assumption you are working with Mongoose - I hope I'm not wrong!
Here is some nice documentation on how Mongoose would fit nicely with koa.
So first of all make sure you are using a version of Mongoose that supports using yield. If not you'll have to use the #remus approach or manually wrap each of your methods so they are yield compatible (i.e. wrapping with promises).
But if you are using a compatible version (4.0 and upwards) then your code would look something like the following:
exports.random_Question = function *() {
var result;
try {
result = yield Questions.findRandom().limit(1).exec();
} catch(e) {
console.log(e.stack);
throw e;
}
console.log("rand q: " + result[0].text);
return result[0].text;
}
Note that I'm assuming the result is an array based on the code you supplied.
The above example doesn't necessarily have to be a generator function. It could also be a normal function that returns a Promise. So alternatively something like this could also be done:
exports.random_Question = function() {
return Questions.findRandom()
.limit(1)
.exec()
.then(function() {
// I'm assuming mongoose assigns the value
// being resolved in exec() to 'this'
var question = this[0];
console.log("rand q: " + question.text);
return question.text;
}).catch(function(e) {
console.log(e.stack);
throw e;
});
}
So for the randomQuestion function all that is important is that it can be yielded by co which handles the Koa application flow control – check tj/co on GitHub for the different objects you can yield.
So finally getting back to the Koa Middleware we can yield either of the above code snippets in the exact same manner. So we'd do:
var koa = require("koa");
var app = module.exports = koa();
var Game_Questions = require('./backend/Game_Questions');
app.use(function*() {
var resultText;
try {
resultText = yield Game_Questions.random_Question();
} catch(e) {
this.throw(500);
}
this.body = resultText;
this.status = 200;
});
app.listen(3000);
Something else to note is that I'm a little unsure of the findRandom method in the mongoose query since I don't know if it plays nicely with the Promise features of mongoose. Personally I'd get a normal mongoose query working using yield before reintroducing findRandom just to make sure it's not causing an issue.
My answer is getting a bit long at this point so I'll leave it at that.
Your syntax is pretty strange, but not sure if that's specific to Koa or not?
Because Node.js is event based, use a callback instead:
exports.random_Question = function(callback) {
Questions.findRandom().limit(1).exec(function(err, question){
callback(err, question);
});
}
And use it:
var Game_Questions = require('./backend/Game_Questions');
Game_Questions.random_Question(function(err, question) {
console.log(question);
});
Of some concern as well is your question states you're trying to reference Game_Questions.randomQuestion() when your function is actually named random_Question.
I've been very excited about Node JS for awhile. I finally decided to knuckle down and write a test project to learn about generators in the latest Harmony build of Node.
Here is my very simple test project:
https://github.com/kirkouimet/project-node
To run my test project, you can easily pull the files from Github and then run it with:
node --harmony App.js
Here's my problem - I can't seem to get Node's asynchronous fs.readdir method to run inline with generators. Other projects out there, such as Galaxy and suspend seem to be able to do it.
Here is the block of code I need to fix. I want to be able to instantiate an object of type FileSystem and call the .list() method on it:
https://github.com/kirkouimet/project-node/blob/4c77294f42da9e078775bb84c763d4c60f21e1cc/FileSystem.js#L7-L11
FileSystem = Class.extend({
construct: function() {
this.currentDirectory = null;
},
list: function*(path) {
var list = yield NodeFileSystem.readdir(path);
return list;
}
});
Do I need to do something ahead of time to convert Node's fs.readdir into a generator?
One important note, I am parsing all class functions as they are created. This lets me handle generator functions differently than normal functions:
https://github.com/kirkouimet/project-node/blob/4c77294f42da9e078775bb84c763d4c60f21e1cc/Class.js#L31-L51
I've been really stumped with this project. Would love any assistance!
Here is what I am trying to accomplish:
Heavy use of classes with a modified version of John Resig's JavaScript Class support with inheritance
Using generators to get inline support for Node's stock async calls
Edit
I've tried to implement your example function and I am running into some trouble.
list: function*(path) {
var list = null;
var whatDoesCoReturn = co(function*() {
list = yield readdir(path);
console.log(list); // This shows an array of files (good!)
return list; // Just my guess that co should get this back, it doesn't
})();
console.log(whatDoesCoReturn); // This returns undefined (sad times)
// I need to use `list` right here
return list; // This returns as null
}
First and foremost, it is important to have a good model in your head of exactly what a generator is. A generator function is a function that returns a generator object, and that generator object will step through yield statements within the generator function as you call .next() on it.
Given that description, you should notice that asynchronous behavior is not mentioned. Any action on a generator on its own is synchronous. You can run to the first yield immediately and then do a setTimeout and then call .next() to go to the next yield, but it is the setTimeout that causes asynchronous behavior, not the generator itself.
So let's cast this in the light of fs.readdir. fs.readdir is an async function, and using it in a generator on its own will have no effect. Let's look at your example:
function * read(path){
return yield fs.readdir(path);
}
var gen = read(path);
// gen is now a generator object.
var first = gen.next();
// This is equivalent to first = fs.readdir(path);
// Which means first === undefined since fs.readdir returns nothing.
var final = gen.next();
// This is equivalent to final = undefined;
// Because you are returning the result of 'yield', and that is the value passed
// into .next(), and you are not passing anything to it.
Hopefully it makes it clearer that what you are still calling readdir synchronously, and you are not passing any callback, so it will probably throw an error or something.
So how do you get nice behavior from generators?
Generally this is accomplished by having the generator yield a special object that represents the result of readdir before the value has actually been calculated.
For (unrealistic) example, yielding a function is a simple way to yield something that represents the value.
function * read(path){
return yield function(callback){
fs.readdir(path, callback);
};
}
var gen = read(path);
// gen is now a generator object.
var first = gen.next();
// This is equivalent to first = function(callback){ ... };
// Trigger the callback to calculate the value here.
first(function(err, dir){
var dirData = gen.next(dir);
// This will just return 'dir' since we are directly returning the yielded value.
// Do whatever.
});
Really, you would want this type of logic to continue calling the generator until all of the yield calls are done, rather than hard-coding each call. The main thing to notice with this though, is now the generator itself looks synchronous, and everything outside the read function is super generic.
You need some kind of generator wrapper function that handles this yield value process, and your example of the suspend does exactly this. Another example is co.
The standard method for the method of "return something representing the value" is to return a promise or a thunk since returning a function like I did is kind of ugly.
With the thunk and co libraries, you with do the above without the example function:
var thunkify = require('thunkify');
var co = require('co');
var fs = require('fs');
var readdir = thunkify(fs.readdir);
co(function * (){
// `readdir` will call the node function, and return a thunk representing the
// directory, which is then `yield`ed to `co`, which will wait for the data
// to be ready, and then it will start the generator again, passing the value
// as the result of the `yield`.
var dirData = yield readdir(path, callback);
// Do whatever.
})(function(err, result){
// This callback is called once the synchronous-looking generator has returned.
// or thrown an exception.
});
Update
Your update still has some confusion. If you want your list function to be a generator, then you will need to use co outside of list wherever you are calling it. Everything inside of co should be generator-based and everything outside co should be callback-based. co does not make list automatically asynchronous. co is used to translate a generator-based async flow control into callback-based flow control.
e.g.
list: function(path, callback){
co(function * (){
var list = yield readdir(path);
// Use `list` right here.
return list;
})(function(err, result){
// err here would be set if your 'readdir' call had an error
// result is the return value from 'co', so it would be 'list'.
callback(err, result);
})
}
#loganfsmyth already provides a great answer to your question. The goal of my answer is to help you understand how JavaScript generators actually work, as this is a very important step to using them correctly.
Generators implement a state machine, the concept which is nothing new by itself. What's new is that generators allow to use the familiar JavaScript language construct (e.g., for, if, try/catch) to implement a state machine without giving up the linear code flow.
The original goal for generators is to generate a sequence of data, which has nothing to do with asynchrony. Example:
// with generator
function* sequence()
{
var i = 0;
while (i < 10)
yield ++i * 2;
}
for (var j of sequence())
console.log(j);
// without generator
function bulkySequence()
{
var i = 0;
var nextStep = function() {
if ( i >= 10 )
return { value: undefined, done: true };
return { value: ++i * 2, done: false };
}
return { next: nextStep };
}
for (var j of bulkySequence())
console.log(j);
The second part (bulkySequence) shows how to implement the same state machine in the traditional way, without generators. In this case, we no longer able to use while loop to generate values, and the continuation happens via nextStep callback. This code is bulky and unreadable.
Let's introduce asynchrony. In this case, the continuation to the next step of the state machine will be driven not by for of loop, but by some external event. I'll use a timer interval as a source of the event, but it may as well be a Node.js operation completion callback, or a promise resolution callback.
The idea is to show how it works without using any external libraries (like Q, Bluebird, Co etc). Nothing stops the generator from self-driving itself to the next step, and that's what the following code does. Once all steps of the asynchronous logic have completed (the 10 timer ticks), doneCallback will be invoked. Note, I don't return any meaningful data with yield here. I merely use it to suspend and resume the execution:
function workAsync(doneCallback)
{
var worker = (function* () {
// the timer callback drivers to the next step
var interval = setInterval(function() {
worker.next(); }, 500);
try {
var tick = 0;
while (tick < 10 ) {
// resume upon next tick
yield null;
console.log("tick: " + tick++);
}
doneCallback(null, null);
}
catch (ex) {
doneCallback(ex, null);
}
finally {
clearInterval(interval);
}
})();
// initial step
worker.next();
}
workAsync(function(err, result) {
console.log("Done, any errror: " + err); });
Finally, let's create a sequence of events:
function workAsync(doneCallback)
{
var worker = (function* () {
// the timer callback drivers to the next step
setTimeout(function() {
worker.next(); }, 1000);
yield null;
console.log("timer1 fired.");
setTimeout(function() {
worker.next(); }, 2000);
yield null;
console.log("timer2 fired.");
setTimeout(function() {
worker.next(); }, 3000);
yield null;
console.log("timer3 fired.");
doneCallback(null, null);
})();
// initial step
worker.next();
}
workAsync(function(err, result) {
console.log("Done, any errror: " + err); });
Once you understand this concept, you can move on with using promises as wrappers for generators, which takes it to the next powerful level.