Ii'm trying to do something like.
function fun1(){
for(var j=0;j<20;j++)
{
var n = j;
console.log("i= "+n);
}
}
function fun2()
{
console.log("In Callback");
}
fun1();
fun2();
its working fine till now and got output as expected.
But, I want to call function fun1() and fun2() asynchronously it means fun2() call before fun1(), b'coz fun1() will take some time for complete the execution as compare to fun2().
How can I achieve this, Node.js provide asynchronous function, Is it already defined function can asynchronous only or we can make them according our need.
There are multiple ways to achieve this in JavaScript (not node-specific, but there are modules that make your life easier):
callbacks
They are somewhat continuations and it is a shame developers were bothered with handling them manually (compilers used to do that themselves). But they work:
function callee(callback) {
setTimeout(function() {
callback(null, 'finished!');
}, 2000);
}
function caller() {
document.write('started!');
callee(function(err, result) {
document.write(result);
});
}
caller();
It is common in the node environment to indicate errors with the first parameter of the callback (like callback(new Error("something wrong!"))).
promises
As callbacks get ugly when nested (imagine 10-20 of them, you'd be screwed debugging this), the idea of promises came up. You might know them as Futures from java. They are built-in to ES6, and you can use them beforehand in the node environment with npm i promise -- many client-side frameworks (e.g. jQuery, AngularJS) have their own implementations. Originally there was Q.
var Promise = require('promise');
function callee() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('finished!');
}, 1000);
});
}
function caller() {
document.write('started!');
callee().then(function(result) {
document.write(result);
});
}
caller();
generators
ES6 has generators. You might know them from python.
They provide asynchronity as well, as they yield new values once they are computed.
I recommend reading Learn ES2015 for more information on that.
My personal opinion is to never ever use generators as they interfere heavily with promises and make debugging really hard.
async/await
ES7 will make life a whole lot easier with async/await. You can basically say that a function will be performed asynchronously and that you want to await a result (once you are in a async function). ES7 async functions is a good start to read on that. It's like
async function callee() {
return (() => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('finished!'), 1000);
})
})();
}
async function caller() {
document.write('started!');
document.write(await callee());
}
// the global async wrapper
(async function() {
caller();
})();
I have tried to provide a better version of #Dominik Schreiber's answer
async function callee() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('finished!'), 1000);
})
}
async function caller() {
console.log('started!');
console.log(await callee());
}
caller();
You can add a callback to the event que with
process.nextTick(callback);
Don't do that, it is almost never what you want.
JavaScript is single threaded so adding a callback still blocks the call of f2.
If you have a function that takes a long time to run run it in a child_process or even better, create a separate micro service for it.
Related
I'm doing some unit testing. The test framework loads a page into an iFrame and then runs assertions against that page. Before each test begins, I create a Promise which sets the iFrame's onload event to call resolve(), sets the iFrame's src, and returns the promise.
So, I can just call loadUrl(url).then(myFunc), and it will wait for the page to load before executing whatever myFunc is.
I use this sort of pattern all over the place in my tests (not just for loading URLs), primarily in order to allow changes to the DOM to happen (e.g. mimick clicking a button, and wait for divs to hide and show).
The downside to this design is that I'm constantly writing anonymous functions with a few lines of code in them. Further, while I have a work-around (QUnit's assert.async()), the test function that defines the promises completes before the promise is run.
I'm wondering if there is any way to get a value from a Promise or wait (block/sleep) until it has resolved, similar to .NET's IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is single-threaded, but I'm hoping that doesn't mean that a function can't yield.
In essence, is there a way to get the following to spit out results in the correct order?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
I'm wondering if there is any way to get a value from a Promise or
wait (block/sleep) until it has resolved, similar to .NET's
IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is
single-threaded, but I'm hoping that doesn't mean that a function
can't yield.
The current generation of Javascript in browsers does not have a wait() or sleep() that allows other things to run. So, you simply can't do what you're asking. Instead, it has async operations that will do their thing and then call you when they're done (as you've been using promises for).
Part of this is because of Javascript's single threadedness. If the single thread is spinning, then no other Javascript can execute until that spinning thread is done. ES6 introduces yield and generators which will allow some cooperative tricks like that, but we're quite a ways from being able to use those in a wide swatch of installed browsers (they can be used in some server-side development where you control the JS engine that is being used).
Careful management of promise-based code can control the order of execution for many async operations.
I'm not sure I understand exactly what order you're trying to achieve in your code, but you could do something like this using your existing kickOff() function, and then attaching a .then() handler to it after calling it:
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}
kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});
This will return output in a guaranteed order - like this:
start
middle
end
Update in 2018 (three years after this answer was written):
If you either transpile your code or run your code in an environment that supports ES7 features such as async and await, you can now use await to make your code "appear" to wait for the result of a promise. It is still programming with promises. It does still not block all of Javascript, but it does allow you to write sequential operations in a friendlier syntax.
Instead of the ES6 way of doing things:
someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});
You can do this:
// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}
wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});
async functions return a promise as soon as the first await is hit inside their function body so to the caller an async function is still non-blocking and the caller must still deal with a returned promise and get the result from that promise. But, inside the async function, you can write more sequential-like code using await on promises. Keep in mind that await only does something useful if you await a promise so in order to use async/await, your asynchronous operations must all be promise-based.
If using ES2016 you can use async and await and do something like:
(async () => {
const data = await fetch(url)
myFunc(data)
}())
If using ES2015 you can use Generators. If you don't like the syntax you can abstract it away using an async utility function as explained here.
If using ES5 you'll probably want a library like Bluebird to give you more control.
Finally, if your runtime supports ES2015 already execution order may be preserved with parallelism using Fetch Injection.
Another option is to use Promise.all to wait for an array of promises to resolve and then act on those.
Code below shows how to wait for all the promises to resolve and then deal with the results once they are all ready (as that seemed to be the objective of the question); Also for illustrative purposes, it shows output during execution (end finishes before middle).
function append_output(suffix, value) {
$("#output_"+suffix).append(value)
}
function kickOff() {
let start = new Promise((resolve, reject) => {
append_output("now", "start")
resolve("start")
})
let middle = new Promise((resolve, reject) => {
setTimeout(() => {
append_output("now", " middle")
resolve(" middle")
}, 1000)
})
let end = new Promise((resolve, reject) => {
append_output("now", " end")
resolve(" end")
})
Promise.all([start, middle, end]).then(results => {
results.forEach(
result => append_output("later", result))
})
}
kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated during execution: <div id="output_now"></div>
Updated after all have completed: <div id="output_later"></div>
First, this is a very specific case of doing it the wrong way on-purpose to retrofit an asynchronous call into a very synchronous codebase that is many thousands of lines long and time doesn't currently afford the ability to make the changes to "do it right." It hurts every fiber of my being, but reality and ideals often do not mesh. I know this sucks.
OK, that out of the way, how do I make it so that I could:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
The examples (or lack thereof) all use libraries and/or compilers, both of which are not viable for this solution. I need a concrete example of how to make it block (e.g. NOT leave the doSomething function until the callback is called) WITHOUT freezing the UI. If such a thing is possible in JS.
"don't tell me about how I should just do it "the right way" or whatever"
OK. but you should really do it the right way... or whatever
" I need a concrete example of how to make it block ... WITHOUT freezing the UI. If such a thing is possible in JS."
No, it is impossible to block the running JavaScript without blocking the UI.
Given the lack of information, it's tough to offer a solution, but one option may be to have the calling function do some polling to check a global variable, then have the callback set data to the global.
function doSomething() {
// callback sets the received data to a global var
function callBack(d) {
window.data = d;
}
// start the async
myAsynchronousCall(param1, callBack);
}
// start the function
doSomething();
// make sure the global is clear
window.data = null
// start polling at an interval until the data is found at the global
var intvl = setInterval(function() {
if (window.data) {
clearInterval(intvl);
console.log(data);
}
}, 100);
All of this assumes that you can modify doSomething(). I don't know if that's in the cards.
If it can be modified, then I don't know why you wouldn't just pass a callback to doSomething() to be called from the other callback, but I better stop before I get into trouble. ;)
Oh, what the heck. You gave an example that suggests it can be done correctly, so I'm going to show that solution...
function doSomething( func ) {
function callBack(d) {
func( d );
}
myAsynchronousCall(param1, callBack);
}
doSomething(function(data) {
console.log(data);
});
Because your example includes a callback that is passed to the async call, the right way would be to pass a function to doSomething() to be invoked from the callback.
Of course if that's the only thing the callback is doing, you'd just pass func directly...
myAsynchronousCall(param1, func);
Async functions, a feature in ES2017, make async code look sync by using promises (a particular form of async code) and the await keyword. Also notice in the code examples below the keyword async in front of the function keyword that signifies an async/await function. The await keyword won't work without being in a function pre-fixed with the async keyword. Since currently there is no exception to this that means no top level awaits will work (top level awaits meaning an await outside of any function). Though there is a proposal for top-level await.
ES2017 was ratified (i.e. finalized) as the standard for JavaScript on June 27th, 2017. Async await may already work in your browser, but if not you can still use the functionality using a javascript transpiler like babel or traceur. Chrome 55 has full support of async functions. So if you have a newer browser you may be able to try out the code below.
See kangax's es2017 compatibility table for browser compatibility.
Here's an example async await function called doAsync which takes three one second pauses and prints the time difference after each pause from the start time:
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
async function doAsync () {
var start = Date.now(), time;
console.log(0);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
}
doAsync();
When the await keyword is placed before a promise value (in this case the promise value is the value returned by the function doSomethingAsync) the await keyword will pause execution of the function call, but it won't pause any other functions and it will continue executing other code until the promise resolves. After the promise resolves it will unwrap the value of the promise and you can think of the await and promise expression as now being replaced by that unwrapped value.
So, since await just pauses waits for then unwraps a value before executing the rest of the line you can use it in for loops and inside function calls like in the below example which collects time differences awaited in an array and prints out the array.
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this calls each promise returning function one after the other
async function doAsync () {
var response = [];
var start = Date.now();
// each index is a promise returning function
var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
for(var i = 0; i < promiseFuncs.length; ++i) {
var promiseFunc = promiseFuncs[i];
response.push(await promiseFunc() - start);
console.log(response);
}
// do something with response which is an array of values that were from resolved promises.
return response
}
doAsync().then(function (response) {
console.log(response)
})
The async function itself returns a promise so you can use that as a promise with chaining like I do above or within another async await function.
The function above would wait for each response before sending another request if you would like to send the requests concurrently you can use Promise.all.
// no change
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
// no change
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async function doAsync () {
var start = Date.now();
// we are now using promise all to await all promises to settle
var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
return responses.map(x=>x-start);
}
// no change
doAsync().then(function (response) {
console.log(response)
})
If the promise possibly rejects you can wrap it in a try catch or skip the try catch and let the error propagate to the async/await functions catch call. You should be careful not to leave promise errors unhandled especially in Node.js. Below are some examples that show off how errors work.
function timeoutReject (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
}, time)
})
}
function doErrorAsync () {
return timeoutReject(1000);
}
var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);
async function unpropogatedError () {
// promise is not awaited or returned so it does not propogate the error
doErrorAsync();
return "finished unpropogatedError successfully";
}
unpropogatedError().then(log).catch(logErr)
async function handledError () {
var start = Date.now();
try {
console.log((await doErrorAsync()) - start);
console.log("past error");
} catch (e) {
console.log("in catch we handled the error");
}
return "finished handledError successfully";
}
handledError().then(log).catch(logErr)
// example of how error propogates to chained catch method
async function propogatedError () {
var start = Date.now();
var time = await doErrorAsync() - start;
console.log(time - start);
return "finished propogatedError successfully";
}
// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)
If you go here you can see the finished proposals for upcoming ECMAScript versions.
An alternative to this that can be used with just ES2015 (ES6) is to use a special function which wraps a generator function. Generator functions have a yield keyword which may be used to replicate the await keyword with a surrounding function. The yield keyword and generator function are a lot more general purpose and can do many more things then just what the async await function does. If you want a generator function wrapper that can be used to replicate async await I would check out co.js. By the way co's function much like async await functions return a promise. Honestly though at this point browser compatibility is about the same for both generator functions and async functions so if you just want the async await functionality you should use Async functions without co.js.
(I recommend just using async/await it's pretty widely supported in most environments that the above strikethrough is supported in.)
Browser support is actually pretty good now for Async functions (as of 2017) in all major current browsers (Chrome, Safari, and Edge) except IE.
Take a look at JQuery Promises:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
Refactor the code:
var dfd = new jQuery.Deferred();
function callBack(data) {
dfd.notify(data);
}
// do the async call.
myAsynchronousCall(param1, callBack);
function doSomething(data) {
// do stuff with data...
}
$.when(dfd).then(doSomething);
You can force asynchronous JavaScript in NodeJS to be synchronous with sync-rpc.
It will definitely freeze your UI though, so I'm still a naysayer when it comes to whether what it's possible to take the shortcut you need to take. It's not possible to suspend the One And Only Thread in JavaScript, even if NodeJS lets you block it sometimes. No callbacks, events, anything asynchronous at all will be able to process until your promise resolves. So unless you the reader have an unavoidable situation like the OP (or, in my case, are writing a glorified shell script with no callbacks, events, etc.), DO NOT DO THIS!
But here's how you can do this:
./calling-file.js
var createClient = require('sync-rpc');
var mySynchronousCall = createClient(require.resolve('./my-asynchronous-call'), 'init data');
var param1 = 'test data'
var data = mySynchronousCall(param1);
console.log(data); // prints: received "test data" after "init data"
./my-asynchronous-call.js
function init(initData) {
return function(param1) {
// Return a promise here and the resulting rpc client will be synchronous
return Promise.resolve('received "' + param1 + '" after "' + initData + '"');
};
}
module.exports = init;
LIMITATIONS:
These are both a consequence of how sync-rpc is implemented, which is by abusing require('child_process').spawnSync:
This will not work in the browser.
The arguments to your function must be serializable. Your arguments will pass in and out of JSON.stringify, so functions and non-enumerable properties like prototype chains will be lost.
There is one nice workaround at http://taskjs.org/
It uses generators which are new to javascript. So it's currently not implemented by most browsers. I tested it in firefox, and for me it is nice way to wrap asynchronous function.
Here is example code from project GitHub
var { Deferred } = task;
spawn(function() {
out.innerHTML = "reading...\n";
try {
var d = yield read("read.html");
alert(d.responseText.length);
} catch (e) {
e.stack.split(/\n/).forEach(function(line) { console.log(line) });
console.log("");
out.innerHTML = "error: " + e;
}
});
function read(url, method) {
method = method || "GET";
var xhr = new XMLHttpRequest();
var deferred = new Deferred();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 400) {
var e = new Error(xhr.statusText);
e.status = xhr.status;
deferred.reject(e);
} else {
deferred.resolve({
responseText: xhr.responseText
});
}
}
};
xhr.open(method, url, true);
xhr.send();
return deferred.promise;
}
What you want is actually possible now. If you can run the asynchronous code in a service worker, and the synchronous code in a web worker, then you can have the web worker send a synchronous XHR to the service worker, and while the service worker does the async things, the web worker's thread will wait. This is not a great approach, but it could work.
let result;
async_function().then(r => result = r);
while (result === undefined) // Wait result from async_function
require('deasync').sleep(100);
In Node.js it's possible to write synchronous code which actually invokes asynchronous operations.
node-fibers allows this. It's a 3rd party native extension provided as an npm module.
It implements fibers/coroutines, so when a specific fiber is blocked waiting for asynchronous operation, the whole program events loop doesn't block - another fiber (if exists) continues its job.
With fibers your code would look like this:
var Fiber = require('fibers');
function doSomething() {
var fiber = Fiber.current;
function callBack(data) {
fiber.run(data);
}
myAsynchronousCall(param1, callBack);
// execution blocks here
var data = Fiber.yield();
return data;
}
// The whole program must be wrapped with Fiber
Fiber(function main() {
var data = doSomething();
console.log(data);
}).run();
Note, that you should avoid it and use async/await instead. See below a note from the project readme https://github.com/laverdet/node-fibers:
NOTE OF OBSOLESCENCE -- The author of this project recommends you avoid its use if possible. The original version of this module targeted nodejs v0.1.x in early 2011 when JavaScript on the server looked a lot different. Since then async/await, Promises, and Generators were standardized and the ecosystem as a whole has moved in that direction.
I'll continue to support newer versions of nodejs as long as possible but v8 and nodejs are extraordinarily complex and dynamic platforms. It is inevitable that one day this library will abruptly stop working and no one will be able to do anything about it.
I'd like to say thank you to all the users of fibers, your support over the years has meant a lot to me.
Using Node 16's worker threads actually makes this possible, The following example the main thread is running the asynchronous code while the worker thread is waiting for it synchronously.
Not that is is very useful, but it at least does vaguely what the original question asked by waiting for asynchronous code synchronously.
const {
Worker, isMainThread, parentPort, receiveMessageOnPort
} = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.on('message', async () => {
worker.postMessage(await doAsyncStuff());
});
} else {
console.log(doStuffSync());
}
function doStuffSync(){
parentPort.postMessage({fn: 'doStuff'});
let message;
while (!message) {
message = receiveMessageOnPort(parentPort)
}
return message;
}
function doAsyncStuff(){
return new Promise((resolve) => setTimeout(() => resolve("A test"), 1000));
}
One thing people might not consider: If you control the async function (which other pieces of code depend on), AND the codepath it would take is not necessarily asynchronous, you can make it synchronous (without breaking those other pieces of code) by creating an optional parameter.
Currently:
async function myFunc(args_etcetc) {
// you wrote this
return 'stuff';
}
(async function main() {
var result = await myFunc('argsetcetc');
console.log('async result:' result);
})()
Consider:
function myFunc(args_etcetc, opts={}) {
/*
param opts :: {sync:Boolean} -- whether to return a Promise or not
*/
var {sync=false} = opts;
if (sync===true)
return 'stuff';
else
return new Promise((RETURN,REJECT)=> {
RETURN('stuff');
});
}
// async code still works just like before:
(async function main() {
var result = await myFunc('argsetcetc');
console.log('async result:', result);
})();
// prints: 'stuff'
// new sync code works, if you specify sync mode:
(function main() {
var result = myFunc('argsetcetc', {sync:true});
console.log('sync result:', result);
})();
// prints: 'stuff'
Of course this doesn't work if the async function relies on inherently async operations (network requests, etc.), in which case the endeavor is futile (without effectively waiting idle-spinning for no reason).
Also this is fairly ugly to return either a value or a Promise depending on the options passed in.
("Why would I have written an async function if it didn't use async constructs?" one might ask? Perhaps some modalities/parameters of the function require asynchronicity and others don't, and due to code duplication you wanted a monolithic block rather than separate modular chunks of code in different functions... For example perhaps the argument is either localDatabase (which doesn't require await) or remoteDatabase (which does). Then you could runtime error if you try to do {sync:true} on the remote database. Perhaps this scenario is indicative of another problem, but there you go.)
This ability of promises includes two key features of synchronous operations as follows (or then() accepts two callbacks).
When you get the result, call resolve() and pass the final result.
In case of error, call reject().
The idea is that the result is passed through the chain of .then() handlers.
const synchronize = (() => {
let chain = Promise.resolve()
return async (promise) => {
return chain = chain.then(promise)
}
})()
I wondered the same thing and noticed that the currently best answer contains the right idea in my mind for most use cases, but forgets to mention a couple of things. When using a global variable to lock execution, we're talking about Semaphores, and there are some packages which implement those (my recommendation: async-sema). I think this makes it a little simpler and cleaner.
import { Sema } from 'async-sema'
const sema = new Sema(1) // allow only one concurrent process
async function doSomething() {
var data;
await sema.acquire();
// only one process gets inside here
data = await myAsynchronousCall(param1);
sema.release();
return data;
}
The advantage is obviously that the rest of your program can still do other things asynchronously, only the single block is kind of forced to be synchronously. Disadvantage is that you have to be careful what and where to lock, try/catch/finally possible errors, etc.
You can also convert it into callbacks.
function thirdPartyFoo(callback) {
callback("Hello World");
}
function foo() {
var fooVariable;
thirdPartyFoo(function(data) {
fooVariable = data;
});
return fooVariable;
}
var temp = foo();
console.log(temp);
The idea that you hope to achieve can be made possible if you tweak the requirement a little bit
The below code is possible if your runtime supports the ES6 specification.
More about async functions
async function myAsynchronousCall(param1) {
// logic for myAsynchronous call
return d;
}
function doSomething() {
var data = await myAsynchronousCall(param1); //'blocks' here until the async call is finished
return data;
}
What is the best practice when designing code that can work with async functions inside callback functions, here is a simplified view of the problem.
There is this update functions that makes some async function calls to update some data to some kind of storage.
function update(){
asyncfn(arg, () => {// Callback code});
}
then there are these two buttons to call the update function
Updatebtn.onClick = update;
UpdateDisplaybtn.onClick = () => {
update();
displayUpdatedData();
}
The second button will cause problems as the displayUpdatedData() will be called before the update() is truly finished as it has an async function call that will not be finished, also i can not specify my own callback in update() as it is used as a callback to the onClick event.
I don't know much about promises but what i know that the async functions i use does not support them.
I am not looking for some kind of workaround, i am looking for the best practice in a situation like this.
UPDATE
After learning that the best practice is using promises i used this YouTube playlist "JavaScript Promises" by The Coding Train to learn about them which was very good and i wanted to share it with anyone who want to learn about Promises.
If you're working with a function that only accepts a call back, you can wrap it inside of a promise so you can leverage async / await. If the function already returns a promise, you can just use the async / await without having to wrap it.
Doing it this way, you can still have your sequential execution of your update and displayUpdatedData functions by simply putting them within an async function and awaiting them.
function callbackFunction (cb) {
// ... stuff is happening
cb('Data from the callback func');
}
async function update() {
return new Promise( (resolve, reject) => {
callbackFunction( (data) => {
resolve(data); // or reject(); if failure
});
});
}
const doThings = async () => {
const result = await update();
console.log(result);
// TODO: Display data from the result
};
doThings();
So if you are looking for best practices, I highly recommend you familiarize yourself with promises. Javascript now supports the async / await syntax, which allows you to await the response of promises, but lets you write your code more or less like an ordinary function. I know you are saying that the async functions you want to use require callbacks, and do not support promises, but you can convert a callback based function to a promise based one (promisify) using libraries like bluebird, or if you are in node, it has a native promisify function of its own.
So then you would end up with something like this:
import cbFn from 'cbFn'; //import or require your callback based function
import {promisify} from 'util';
const pFn = promisify(cbFn);
async function update() {
await pFn()
}
...
UpdateDisplaybtn.onClick = async () => {
await update();
await displayUpdatedData() //await only needed if displayUpdatedData is also async / a promise
}
I'm currently writing small NodeJS CLI tool for personal usage and I've decided to try ES7 async/await feature with Babel.
It's a network tool so I obviously have asynchronous network requests. I wrote a simple wrapper for request package:
export default function(options) {
return new Promise(function(resolve, reject) {
request({...options,
followAllRedirects: true,
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"
}
}, (error, response, body) => {
if(error) {
return reject(error);
}
resolve({response: response, body: body});
});
});
}
Now I can do something like
async function getGooglePage() {
try {
var r = await request({url: "http://google.com"});
console.log(r.body);
console.log("This will be printed in the end.")
} catch(e) {
console.log(e);
}
}
getGooglePage();
And now I have a question: I do requests in many places and I have to mark all these functions as async, is it a good practice? I mean that almost every function in my code should be async because I need to await a result from other async functions. That's why I think that I misunderstood async/await concept.
async/await is sometimes called "contagious" or "viral" (or so it has in the C# world), because in order for it to be effective, it needs to be supported all the way down the call chain. Forcing something asynchronous to act synchronous can lead to unintended results, so you should extend it from the original method all the way down to the top level consumer using it. In other words, if you create or use a type that uses it, that type should also implement it, and so on all the way up the chain. So yes, it's expected that you add async to every function that itself relies on it. Just note, however, you should not add preemptively add async to functions that don't actually implement or need it.
Just think: If you use async (by awaiting something, I mean), you are async. Avoid squashing an async call into something synchronous.
I do requests in many places and I have to mark all these functions as async
Yes, if all your code is asynchronous, then you'd use async functions everywhere.
Having all your code be asynchronous makes things complicated though. You have to worry about race conditions everywhere, make sure to handle reentrant functions correctly, and remember that during every await basically anything can happen.
I mean that almost every function in my code should be async because I need to await a result from other async functions.
This might not be a best practise. You could try to break down your code into smaller units, most of which are usually not asynchronous. So instead of writing
async function getXandThenDoY(xargs) {
let res = await get(xargs);
…
return …;
}
you should consider making two functions
function doY(res) {
// synchronous
…
return …;
}
function getXandDoY(xargs) {
// asynchronous
return get(xargs).then(doY);
}
/* or, if you prefer:
async function getXandDoY(xargs) {
return doY(await get(xargs));
}
*/
I had the same question.
And found a great answer here → ‘Pitfall 3: your whole stack needs to be async’
No, async/await is not contagious. (I believed the same thing for some time, too)
You can always treat the result of a sync function like a promise, and you are back to normal.
From developer.mozilla.org:
The async function declaration defines an asynchronous function…
Return value:
A Promise which will be resolved with the value
returned by the async function, or rejected with an uncaught exception
thrown from within the async function.
Sample code:
const log = console.log; // just lazy shorthand
// just to delay, as seen in many places
function promiseTimeout(time, value) {
return new Promise(function(resolve, reject) {
setTimeout(function() { resolve(value); }, time);
});
};
// the thing you care about
async function foo() {
Promise.resolve('here')
.then((a) => {log('doing stuff '+a); return 'pear'})
.then(function(v) {
return promiseTimeout(1000,v)
});
};
// treat async-function like promise:
foo().then(function(){ log('folling up in main, ')});
// log('bad end');
gets you:
doing stuff here
following up in main
Enabling 'bad end' would show up too early. You can only await stuff it you use await. (And if you do, remember: It's just syntactic sugar, saving you of stuffing your follow-up code into .then() clasuses... nice, but no more than that.)
I'm doing some unit testing. The test framework loads a page into an iFrame and then runs assertions against that page. Before each test begins, I create a Promise which sets the iFrame's onload event to call resolve(), sets the iFrame's src, and returns the promise.
So, I can just call loadUrl(url).then(myFunc), and it will wait for the page to load before executing whatever myFunc is.
I use this sort of pattern all over the place in my tests (not just for loading URLs), primarily in order to allow changes to the DOM to happen (e.g. mimick clicking a button, and wait for divs to hide and show).
The downside to this design is that I'm constantly writing anonymous functions with a few lines of code in them. Further, while I have a work-around (QUnit's assert.async()), the test function that defines the promises completes before the promise is run.
I'm wondering if there is any way to get a value from a Promise or wait (block/sleep) until it has resolved, similar to .NET's IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is single-threaded, but I'm hoping that doesn't mean that a function can't yield.
In essence, is there a way to get the following to spit out results in the correct order?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
I'm wondering if there is any way to get a value from a Promise or
wait (block/sleep) until it has resolved, similar to .NET's
IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is
single-threaded, but I'm hoping that doesn't mean that a function
can't yield.
The current generation of Javascript in browsers does not have a wait() or sleep() that allows other things to run. So, you simply can't do what you're asking. Instead, it has async operations that will do their thing and then call you when they're done (as you've been using promises for).
Part of this is because of Javascript's single threadedness. If the single thread is spinning, then no other Javascript can execute until that spinning thread is done. ES6 introduces yield and generators which will allow some cooperative tricks like that, but we're quite a ways from being able to use those in a wide swatch of installed browsers (they can be used in some server-side development where you control the JS engine that is being used).
Careful management of promise-based code can control the order of execution for many async operations.
I'm not sure I understand exactly what order you're trying to achieve in your code, but you could do something like this using your existing kickOff() function, and then attaching a .then() handler to it after calling it:
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}
kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});
This will return output in a guaranteed order - like this:
start
middle
end
Update in 2018 (three years after this answer was written):
If you either transpile your code or run your code in an environment that supports ES7 features such as async and await, you can now use await to make your code "appear" to wait for the result of a promise. It is still programming with promises. It does still not block all of Javascript, but it does allow you to write sequential operations in a friendlier syntax.
Instead of the ES6 way of doing things:
someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});
You can do this:
// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}
wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});
async functions return a promise as soon as the first await is hit inside their function body so to the caller an async function is still non-blocking and the caller must still deal with a returned promise and get the result from that promise. But, inside the async function, you can write more sequential-like code using await on promises. Keep in mind that await only does something useful if you await a promise so in order to use async/await, your asynchronous operations must all be promise-based.
If using ES2016 you can use async and await and do something like:
(async () => {
const data = await fetch(url)
myFunc(data)
}())
If using ES2015 you can use Generators. If you don't like the syntax you can abstract it away using an async utility function as explained here.
If using ES5 you'll probably want a library like Bluebird to give you more control.
Finally, if your runtime supports ES2015 already execution order may be preserved with parallelism using Fetch Injection.
Another option is to use Promise.all to wait for an array of promises to resolve and then act on those.
Code below shows how to wait for all the promises to resolve and then deal with the results once they are all ready (as that seemed to be the objective of the question); Also for illustrative purposes, it shows output during execution (end finishes before middle).
function append_output(suffix, value) {
$("#output_"+suffix).append(value)
}
function kickOff() {
let start = new Promise((resolve, reject) => {
append_output("now", "start")
resolve("start")
})
let middle = new Promise((resolve, reject) => {
setTimeout(() => {
append_output("now", " middle")
resolve(" middle")
}, 1000)
})
let end = new Promise((resolve, reject) => {
append_output("now", " end")
resolve(" end")
})
Promise.all([start, middle, end]).then(results => {
results.forEach(
result => append_output("later", result))
})
}
kickOff()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Updated during execution: <div id="output_now"></div>
Updated after all have completed: <div id="output_later"></div>