How to force javascript wait/block until deferred jobs done? - javascript

I have some code like:
var filteredData = [];
asyncFunc().done(function () {
filteredData = blablabla...
});
return filteredData;
This is a project to deliver soon. I cannot change it to callback or $.Deffered due to the existing code/design.
Is it possible to force it to wait until aysncFunc have done its jobs and then return the real filteredData that I want?
EDIT:
#MerynStol you're right. Async was sent to last of the job queue(I forgot the term), which is after while and return. So when while ends, return execute immediately.
Should I keep on this or try to bargain more time for a re-structure?

You could extend the Function prototype:
Function.prototype.and = Function.prototype.and || function(fn){
this();
var args = [].slice.call(arguments), arg;
while (args.length) {
arg = args.shift();
if (arg instanceof Function) {
arg();
}
}
}
and use it with a comma operator like this:
var filteredData = [];
return (asyncFunc.and( function () {
filteredData = /* do stuff */
} ), filteredData);
Or if method done works as expected just use:
var filteredData = [];
return (asyncFunc().done(function () {
filteredData = /*blablabla...*/
}), filteredData);

Related

How to interupt Array.push with Proxy?

I want to add a side effect every when an array being pushed. For example, I want to add console.log:
var arr = [];
arr.push(1); // => I want it to work normally, and in addition, it logs 1 to the console
How to achieve that? I'm looking for a solution using Proxy and I have tried handler.get() and handler.apply() but still, can't figure it out.
To directly answer your initial question...you need to return a closure from the get trap. To actually trap this, you would need to use proxy.push() instead of array.push(), though. For example:
const arr = [];
const arrProxy = new Proxy(arr, {
get(target, prop) {
if (prop === 'push') {
return (...args) => {
console.log(...args);
return target[prop](...args);
};
}
return target[prop];
}
});
arrProxy.push('test');
arrProxy.push('test1', 'test2');
Here's the final answer that I'm comfortable with, it doesn't use Proxy by the way.
{
var arr = [];
// add push
arr.push = function (...items) {
console.log(...items);
Array.prototype.push.apply(this, items);
};
arr.push('test');
arr.push('test1');
// clean up the push
delete arr.push;
}
something like that ?
Object.defineProperty(Array.prototype, 'myPush',
{
value : function (...val)
{
console.log(...val)
return this.push(...val)
}
})
let aa = []
aa.myPush( 5,123)
console.log('aa = ', aa )

Test to check if array is reversed in place

I have a method which I have put on the array prototype that reverses the array (this is done for learning purposes only). This method should reverse the array in place.
Array.prototype.yarra = function () {
for (let left=0, right=this.length-1; left<right; left++, right--) {
[this[left], this[right]] = [this[right], this[left]]
}
return this
};
I have written some tests to check if the method works as expected.
describe('yarra', function () {
it('should reverse an array in place and return it', function () {
var arr = [1,2,3];
var reversedArr = arr.yarra();
reversedArr.should.eql([3,2,1]);
arr.should.equal.reversedArr;
[4,5,6].yarra().should.eql([6,5,4]);
});
});
I realise the tests don't work as expected as I reversed the array out of place and returned a new array, and it still passed. Also, because var reversedArr = arr.yarra() means arr will always equal reversedArr, so it doesn't really check for anything.
How would I write a test that can check if the array is reversed in place?
const assert = require('assert');
Array.prototype.yarra = function () {
for (let left=0, right=this.length-1; left<right; left++, right--) {
[this[left], this[right]] = [this[right], this[left]]
}
return this
};
describe('yarra1', () => {
it('should reverse an array in place and return it', () => {
let arr = [1,2,3];
let rev = [3,2,1];
let reversedArr = arr.yarra();
for(let i =0;i<arr.length;i++){
assert(reversedArr[i]===rev[i])
}
});
});
describe('yarra2', () => {
it('should reverse an array in place and return it', () => {
let arr = [1,2,3];
let rev = [3,2,1];
let reversedArr = arr.yarra();
assert(reversedArr.toString() === rev.toString())
});
});

How can I completely exit from inside a .forEach that is inside a function

I have this method:
wordFormDirty = (): boolean => {
var self = this;
angular.forEach(self.word.wordForms, function (wf, key) {
var wordFormNgForm = 'wordFormNgForm_' + wf.wordFormId
if (!self[wordFormNgForm].$pristine) {
return true;
}
});
return false;
};
From what I see this never returns true. Can someone give me advice as to how I can implement this so that a form that's not pristine will make the wordFormDirty() method return true.
can you try this, in this case, if I've undestand the issue, the first time there is a value true the result is set to true otherwise it remains false
wordFormDirty = (): boolean => {
var self = this;
var result = false;
angular.forEach(self.word.wordForms, function (wf, key) {
var wordFormNgForm = 'wordFormNgForm_' + wf.wordFormId
if (!self[wordFormNgForm].$pristine) {
result = true;
}
});
return result;
};
If you wish to get a result directly from walking the Array, consider using other methods than forEach. E.g.:
return Object.values(this.word.wordForms).some(
({ wordFormId }) => !this[`wordFormNgForm_${wordFormId}`].$pristine
);

I want to not be able to run the same command twice very quickly

So I have this chunk of code here:
lockskipCommand = (function(_super) {
__extends(lockskipCommand, _super);
function lockskipCommand() {
return lockskipCommand.__super__.constructor.apply(this, arguments);
}
lockskipCommand.prototype.init = function() {
this.command = '/lockskip';
this.parseType = 'exact';
return this.rankPrivelege = 'bouncer';
};
lockskipCommand.prototype.functionality = function() {
data.lockBooth();
new ModerationForceSkipService();
return setTimeout((function() {
return data.unlockBooth();
}), 4500);
};
return lockskipCommand;
})(Command);
I want to be able to let it has some sort of cool down, so it can't be used quickly in a row. The reason I want this is to prevent from people being skipped, because that's what this chunk of code is for skipping people.
I hope this is enough information to get some help. Thanks!
You can use Underscore's debounce() method (with true as the third argument).
If you don't want to include Underscore for this simple task, you could do...
var debounceFn = function (fn, delay) {
var lastInvocationTime = Date.now();
delay = delay || 0;
return function () {
(Date.now() - delay > lastInvocationTime) && (lastInvocationTime = Date.now()) && fn && fn();;
};
};
jsFiddle.
What I need is a way to not be able to execute the command more than once in a row.
You could do something similar...
var onceFn = function (fn) {
var invoked = false;
return function () {
! invoked && (invoked = true) && fn && fn();
};
};
jsFiddle.

How can I extend Array.prototype.push()?

I'm trying to extend the Array.push method so that using push will trigger a callback method and then perform the normal array function.
I'm not quite sure how to do this, but here's some code I've been playing with unsuccessfully.
arr = [];
arr.push = function(data){
//callback method goes here
this = Array.push(data);
return this.length;
}
arr.push('test');
Since push allows more than one element to be pushed, I use the arguments variable below to let the real push method have all arguments.
This solution only affects the arr variable:
arr.push = function () {
//Do what you want here...
return Array.prototype.push.apply(this, arguments);
}
This solution affects all arrays. I do not recommend that you do that.
Array.prototype.push = (function() {
var original = Array.prototype.push;
return function() {
//Do what you want here.
return original.apply(this, arguments);
};
})();
First you need subclass Array:
ES6 (https://kangax.github.io/compat-table/es6/):
class SortedArray extends Array {
constructor(...args) {
super(...args);
}
push() {
return super.push(arguments);
}
}
ES5 (proto is almost deprecated, but it is the only solution for now):
function SortedArray() {
var arr = [];
arr.push.apply(arr, arguments);
arr.__proto__ = SortedArray.prototype;
return arr;
}
SortedArray.prototype = Object.create(Array.prototype);
SortedArray.prototype.push = function() {
this.arr.push(arguments);
};
Array.prototype.push was introduced in JavaScript 1.2. It is really as simple as this:
Array.prototype.push = function() {
for( var i = 0, l = arguments.length; i < l; i++ ) this[this.length] = arguments[i];
return this.length;
};
You could always add something in the front of that.
You could do it this way:
arr = []
arr.push = function(data) {
alert(data); //callback
return Array.prototype.push.call(this, data);
}
If you're in a situation without call, you could also go for this solution:
arr.push = function(data) {
alert(data); //callback
//While unlikely, someone may be using "psh" to store something important
//So we save it.
var saved = this.psh;
this.psh = Array.prototype.push;
var ret = this.psh(data);
this.psh = saved;
return ret;
}
While I'm telling you how to do it, you might be better served with using a different method that performs the callback and then just calls push on the array rather than overriding push. You may end up with some unexpected side effects. For instance, push appears to be varadic (takes a variable number of arguments, like printf), and using the above would break that.
You'd need to do mess with _Arguments() and _ArgumentsLength() to properly override this function. I highly suggest against this route.
Or you could use "arguments", and that'd work too. I still advise against taking this route though.
There's another, more native method to achieve this: Proxy
const target = [];
const handler = {
set: function(array, index, value) {
// Call callback function here
// The default behavior to store the value
array[index] = value;
// Indicate success
return true;
}
};
const proxyArray = new Proxy(target, handler);
I wanted to call a function after the object has been pushed to the array, so I did the following:
myArray.push = function() {
Array.prototype.push.apply(this, arguments);
myFunction();
return myArray.length;
};
function myFunction() {
for (var i = 0; i < myArray.length; i++) {
//doSomething;
}
}

Categories

Resources