I'm hoping to create a queryBuilder object, and defer execution until I'm ready. The following code allows me to pass a queryBuilder object between functions without executing the query.
const getQueryBuilder = () =>
knex({ client: "mysql2" }).queryBuilder();
const getBaseSelect = () =>
getQueryBuilder().select().from('foo');
const getOne = () =>
getBaseSelect().limit(1);
console.log(getBaseSelect()); // select * from `foo`
console.log(getOne()); // select * from `foo` limit 1
My question is how do I then execute the query that I've constructed in the queryBuilder?
Or is there a better way to construct queries from multiple synchronous functions before executing?
Thanks.
You want to 'defer execution until' you are 'ready.'
It will depend on what you mean by 'ready', but you can fire the query when the desired action is finished using Promise.
For example, if you want to execute the query after 5 seconds delay, using the example from MDN Promise doc, you can do something like this:
let myFirstPromise = new Promise((resolve, reject) => {
// We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
// In this example, we use setTimeout(...) to simulate async code.
// In reality, you will probably be using something like XHR or an HTML5 API.
setTimeout(function(){
resolve("After this value is resolved with 5000ms delay, "); // Yay! Everything went well!
}, 5000);
});
myFirstPromise.then((successMessage) => {
// successMessage is whatever we passed in the resolve(...) function above.
// It doesn't have to be a string, but if it is only a succeed message, it probably will be.
// You can fire your query here
console.log(successMessage + "you can execute your query inside this then(..) function!");
// execute(getBaseSelect());
});
If you are waiting on multiple promises, you can use Promise.all(..) like this:
Promise.all([myFirstPromise, mySecondPromise, myThirdPromise])
.then((values) => {
return execute(values[0], values[1], values[2])
});
Related
For the past 2 days I have been struggling on this thing. I want to watch for changes on particular collection. All of the logic for these changes is in asynchronous way. I tried to make the EventEmitter callback function to be asynchronous but still works in synchronous manner.
Pseudo code example:
const someLogicFunction1 = async () => {
// some logic here
}
const someLogicFunction2 = async () => {
// some logic here
}
const collectionEventEmitter = Collection.watch();
collectionEventEmitter.on('change', async (change) => {
await someLogicFunction1();
await someLogicFunction2(); // has to wait for first function to finish
});
As I explained above I tried this approach but still runs synchronously. The second function usually has to wait for the first function to finish its task in order for the whole code to be properly working.
EDIT:
From what I have found it seems that the callback function firstly gets all this "change" parameter event objects and then executes the code. What I need actually is to execute the code for every "change" event parameter - not for all of them at once.
One solution is to make someLogicFunction1() returning a promise and calling someLogicFunction2(); in then of first function, like this:
await someLogicFunction1()
.then(function(){
someLogicFunction2();
});
You just need to modify someLogicFunction1(); like this:
someLogicFunction1( )
{
return new Promise( async function( resolve, reject ) {
// Do your stuff here
}); // eo promise
}
Don't forget to resolve() in someLogicFunction1 function.
resolve();
You can also reject() in someLogicFunction1 and catch the error when you call this function.
reject();
You can pass an argument to resolve and reject and get it in your call.
I am writing a browser-based javascript to scrape the input value by user and provide feedback. And in the page, you have to click on different areas for the desired element to show. I am trying to see if there is a way I can get javascript to wait until the element returns before I start going to the next one. Right now I just use setTimeout, but I have to loop all the elements I want to get, so nasty nested functions. trying to see if there is a more elegant solution. I used to write VBA, so I am not so familiar with async web API. still learning
function a(){
document.getElementById('1').click()
setTimeout(function(){document.getElementById('1a');addmessage;b;}),5000}
}
function b(){
document.getElementById('2').click()
setTimeout(function(){document.getElementById('2a');addmessage;c;}),5000}
}
function c(){
document.getElementById('3').click()
setTimeout(function(){document.getElementById('3a');addmessage;d;}),5000}
}
function addmessage(){
//this is the function I used to add element do some operation and add to dialog box
}
etc..
what I imagined is like below
function addmessage(element_to_click,element_to_collect){
// click element_to_click
// wait 5s
// collect innertext from element_to_collect
// do some operation, generate a message
//add message to dialog box
}
so I can do something like
addmessage(1,1a)
addmessage(2,2a) <--- this won't execute until the first is complete.
If I'm understanding the question correctly, you can start with a promise wrapper around setTimeout:
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
Then addMessage could be:
async function addMessage(element_to_click, element_to_collect) {
element_to_click.click();
await delay(5000);
return element_to_collect.textContent;
}
You didn't say what you wanted to do with the text, so I've just had it return it.
Then you can either write a loop or a series of calls:
async function run() {
const a = await addMessage(
document.getElementById("1"),
document.getElementById("???"),
);
const b = await addMessage(
document.getElementById("2"),
document.getElementById("???"),
);
const c = await addMessage(
document.getElementById("2"),
document.getElementById("???"),
);
// ...do something with `a`, `b`, and `c`...
}
When calling run, don't forget to handle promise rejection (in case something goes wrong).
You've said that after the click, "...the page needs a few seconds to load..." Hardcoded timeouts are fragile and often break. Instead of a timeout, try to hook into something that will change, perhaps via a MutationObserver on the element you're "collecting" from.
You can make your code wait for a timeout to complete by wrapping it in a Promise and using the async await pattern:
// Return a new Promise immediately, that completes at the end of the timeout
function addmessage(element_to_click, element_to_collect) {
return new Promise((resolve, reject) => {
// do whatever
// resolve the Promise after 5s
setTimeout(resolve, 5000)
// you can also resolve the Promise on any other event, like user input
// (or use `reject` when an error occurs)
// you can pass a return value to `resolve` like resolve(input.value)
})
}
// `async` functions also return a Promise immediately
async function addMessages() {
// `await` will block until Promise completes and
// returns the resolved value to be used synchronously within the async func
const in1 = await addmessage('1', '1a')
const in2 = await addmessage('2', '2a')
const in3 = await addmessage('3', '3a')
}
addMessages()
I have the following code:
function MyPromise(configFunction) {
let nextSuccessCallBack = undefined;
let nextResolve = undefined;
configFunction(function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
});
return {
then: function(successCallback) {
nextSuccessCallBack = successCallback;
return new MyPromise(function(resolve) {
nextResolve = resolve;
})
}
}
}
new MyPromise(function(resolve, reject) {
resolve('new message');
}).then(function(message) {
console.log(message);
return 'another message'
}).then(function(message) {
console.log(message)
console.log('here')
})
In this example, it seems that the nextSuccessCallBack is set to be the callback functions within .then, then its value within the setTimeout function is now populated. However, this confuses me. I thought that when we reach the return statement in the constructor, we return the object and effectively stop the function? If that the case then how does the program even get to the setTimeout?
This is not a correct Promise implementation. It clearly has no capabilities for rejections, but also for the implemented fulfilment feature it does not comply with the Promises/A+ specification. Just to give two examples:
It does not comply with rule 2.1.2.2
When fulfilled, a promise must have a value, which must not change.
....nor with rule 2.2.2.3:
If onFulfilled is a function it must not be called more than once.
In your implementation, if you would add a second call to resolve:
new MyPromise(function(resolve, reject) {
resolve('new message'); resolve('new message2');
}).then((function(message) {
console.log(message);
// ... etc
})
...then both calls to resolve would fire the then callback, and show that the promised value was modified after the first time it was set. This is in complete violation of the principle of promises: promises can only resolve once.
It does not comply with rule 2.2.6:
then may be called multiple times on the same promise.
If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
This does not happen if we use the following code:
let p = new MyPromise(resolve => resolve("value"));
p.then(console.log); // This callback is called
p.then(console.log); // This callback is not called -> violation!
These are basic shortcomings, and this is just the tip of the iceberg.
If you are interested in how it could be implemented in compliance with Promise/A+, then have a look at one I did a few years ago with a step-by-step explanation.
As to your question
how does the program even get to the setTimeout?
When your main code executes this:
new MyPromise(function(resolve, reject) {
resolve('new message');
})
...then the parameter variable configFunction is initialised with that callback function. The MyPromise constructor calls it, passing it the following callback as first argument:
function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
}
So that means that resolve in your main code's callback function is initialised with the above callback function. Then your main code's callback function calls resolve with a string argument. Since resolve is the above callback function, we can see it gets executed with message initialised to "new message". This function executes setTimeout.
The code in the snippet does solve the purpose but, it is confusing as is a bad implementation of a Promise according to the way MDN Uses Promises in JavaScript for better code efficiency and understanding.
The above code can also be written this way:
const examplePromise = new Promise((resolve, reject) => {
resolve("Another Message");
});
console.log("New Message");
examplePromise.then((message) => {
console.log(message);
});
Now, for better understading of the concept of Promises in JavaScript, I'll take another example:
Let's say I want to create a program which says hello and then after 2 seconds says How Are You?
There are two ways of solving this
Just using the setTimeout() function which executes a function after certain period of time
Using promises with setTimeout()
Case I (Using setTimeout()):
console.log("hello"); //Saying hello for the first time
setTimeout(function () {
console.log("How Are You?");
}, 2000); //2000 milliseconds is 2 seconds
Case II (Using Promises)
console.log("hello");
const example = new Promise((resolve) => {
setTimeout(() => {
resolve("How Are You?");
}, 2000);
});
example.then((message) => {
console.log(message);
});
Now, for simple cases like logging a message after 2 seconds do not require Promises. You may use them (No problem) but actually, Promises are used in cases where, you wait for a function to execute a Database Query or you need to wait for a server to give you some HTML Response or while using WebAPIs, etc.
P.S: setTimeout() is just an example. It is not a rule that you always have to use setTimeout() while writing a Promise. If you are fetching data using a WebAPI, you usually write $.ajax(...).then(...) or fetch(...).then(...) instead of setTimeout()
I don't have any problem in this question, I am just interested in how knex.js menaged to something.
In code, you can write something like this
let search = knex.table('users').select('something')
if(params.minprice) search.where('minprice', params.minprice)
if(something) search.something()
let result = await search
It works, but I don't get how did they menage to hold query execution until await occured? If we did await, it means function was async aka returned a promise. But in javascript, promise executes as soon as function that returned it is called, it does not care is there .then() or .catch(). Should not query execution start al line 1? What is more, when I log search, it is not a promise, but some kind of object, so how can it be awaited?
Can someone provide a simple example how to achieve such a behaviour?
I'm guessing that search contains a property named then, which is a function that initiates the search and also behaves similarly to the functionality of Promise.prototype.then.
E.g.:
// define Searchable
let Searchable = function() {
this.searchParam = 'param';
};
Searchable.prototype = {
setSearchParam: function(p) { this.searchParam = p; },
initiateSearch: async function() {
// lots of fancy searching
console.log(`Searching with param "${this.searchParam}"`);
return `search based on "${this.searchParam}"`;
},
then: async function(callback) {
// initiate the search:
let searchResults = await this.initiateSearch();
// behave kind of like `Promise.prototype.then`!
return callback(searchResults);
}
};
// now work with it:
(async () => {
let searchable = new Searchable();
searchable.setSearchParam('mySearchParam');
console.log('No search performed yet!');
// Here's the fancy usage you're concerned with (it invokes `searchable.then`):
let searchResult = await searchable;
console.log('RESULT:', searchResult);
})();
Calling await on some value will attempt to call value.then as if it were a function accepting a callback argument.
Knex query builder is mutable and thenable object.
So every time you call for example search.where(...) for that query builder, its internal state changes and stores that new where clause.
Query builder being thenable means that the object has .then() method and when you call await search it is actually pretty much equivalent with await Promise.resolve(search) which first executes thenable and converts it to promise which is then resolved or an exception might occur.
Thenable objects are actually pretty important part of promise spec providing interoperability API between promises and non-promise objects.
I'm trying to understand the differences between es6 promises and regular callbacks but don't get the examples below. Can someone show what it would look like to do the below with callbacks?
// an immediately resolved promise
var p2 = Promise.resolve("foo");
// can get it after the fact, unlike events
p2.then((res) => console.log(res));
var p = new Promise(function(resolve, reject) {
setTimeout(() => resolve(4), 2000);
});
// handler can't change promise, just value
p.then((res) => {
res += 2;
console.log(res);
});
// still gets 4
p.then((res) => console.log(res));
A promise is a one-way latch. Once it is resolved with a value or rejected with a reason, its state and value/reason can never change. So, no matter how many times you do .then() on the same promise, you will always get the same result. That's what "immutable" means.
I'm not sure what you mean by a guaranteed value. There is no guarantee that a promise will ever resolve. It might reject (and thus not have a value) or it might never resolve or reject if the operation just never completes.
An example of the type of operation promises are designed for is an asynchronous operations such as an Ajax call or reading some bytes from a file. The operation is asynchronous (normal execution of the interpreter continues after the operation was started) and the operation has a specific start and end to it. In most case, the operation may complete successfully in which case it can have a value or it may end with an error in which case it has an error. Both value and error can be objects so they can have many properties if the result is more than a simple value.
An Ajax call, for example has a specific start and end. It can't end more than once so it is a perfect match for promises. You get a promise that signifies the eventual result of the ajax operation. You then register both a fulfill handler and a reject handler and one or the other will be called when the operation has completed.
Plain callbacks are just callbacks and they can be given a different value every time they are called and they can be called more than once.
If you want to get notified once and only once when some operation completes and the operation has a specific begin and end, use a promise.
If you want to get notified more than once, use a plain callback or an event listener or an observer or some other mechanism that can be trigger more than once.
As a simple example, setTimeout() works very well with a promise.
function delay(t) {
return new Promise((resolve, reject) => {
resolve();
}, t);
}
// delay 100ms before starting the operation
delay(100).then(run);
Or, a little more involved operation using the Bluebird Promise library to cycle through a list of URLs, download the content, parse the content, look in the content for some specific URLs and then collect them all (otherwise known as scraping):
const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'), {multiArgs: true});
const cheerio = require('cheerio');
function getAsync() {
return request.getAsync.apply(request, arguments).then(argArray => {
// return only the response html
if (argArray[0].statusCode !== 200) {
throw new Error("response statusCode = " + argArray[0].statusCode);
}
return argArray[1];
});
}
const urls = [....];
Promise.mapSeries(urls, url => {
return getAsync({url: url, gzip: true}).then(html => {
let $ = cheerio.load(html);
let resources = $("#external_resources_list li a.filename");
resources.each(index, link) => {
let href = $(link).attr("href");
console.log(href);
results.push(href);
});
}).catch(err => {
// log error, but keep going
console.log(url, err);
});
}).then(() => {
// got all results here
console.log(results);
});
And, setInterval() does not work at all with a promise because it wants to notify you repeatedly everytime the time interval passes and that will simply not work with promises. Stick with a callback for setInterval().
To make the comparison with a standard callback system, let's create a class that can produce such notifier objects. It will have an interface much like Promise has, but which implements a simple callback system:
class Notifier {
constructor(executor) {
// The object will maintain a list of callbacks
this.callbacks = [];
// The executor is executed now and will allow the client
// to determine the logic of this notifier object:
// ...when the callbacks need to be called and with which value:
executor( (res) => {
// The client can call this resolve function to indicate
// the value. So now the callbacks need to be called with it:
this.callbacks.forEach(callback => callback(res));
});
}
addListener(callback) {
// This method resembles the `then` of promises: it allows
// a client to pass a callback function, that should be called
// when the value becomes available (i.e. when the event triggers).
this.callbacks.push(callback);
}
};
So, like with Promise, you can pass to the constructor of this class a function to do some work and indicate the value at the appropriate time. You can also attach listeners to it, which will be called at the moment the value becomes available.
This last phrase highlights an important fact: if the value becomes available, but you did not attach a listener (callback) yet, you'll miss the notification, even if you attach the listener after the facts.
Here is the callback-based code which you could compare with the code you quoted from the article:
class Notifier {
constructor(executor) {
// The object will maintain a list of callbacks
this.callbacks = [];
// The executor is executed now and will allow the client
// to determine the logic of this notifier object:
// ...when the callbacks need to be called and with which value:
executor( (res) => {
// The client can call this resolve function to indicate
// the value. So now the callbacks need to be called with it:
this.callbacks.forEach(callback => callback(res));
});
}
addListener(callback) {
// This method resembles the `then` of promises: it allows
// a client to pass a callback function, that should be called
// when the value becomes available (i.e. when the event triggers).
this.callbacks.push(callback);
}
};
// a notifier that immediately notifies the result
f2 = new Notifier( (resolve) => resolve("foo") );
// but since no-one was listening, no callback is called.
// canNOT get it after the fact, unlike promises
f2.addListener((res) => console.log(res));
// ... nothing gets called or printed: we are too late.
//
var f = new Notifier(function(resolve) {
setTimeout(() => resolve({ data: 4}), 2000);
});
// handler CAN change the outcome
f.addListener((res) => {
res.data += 2;
console.log(res.data);
});
// ... now also this one gets 6!
f.addListener((res) => console.log(res.data));
when the promise variable is resolved, the value resolved when it is recalled returns.
to use more than one, you must call it as follows.
var p = new Promise(function(resolve, reject) {
setTimeout(() => resolve(4), 2000);
});
p.then((res) => {
res += 2;
console.log(res);
return res
})
.then((res) => console.log(res));