Skip to content

Commit

Permalink
Build asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
Vova Bilonenko committed Sep 1, 2012
1 parent e592cd2 commit 516ea68
Show file tree
Hide file tree
Showing 4 changed files with 369 additions and 14 deletions.
5 changes: 5 additions & 0 deletions i-bem/__json/_async/i-bem__json_async_yes.deps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
({
mustDeps: [
{block: 'i-bem', elem: 'json' }
]
});
94 changes: 94 additions & 0 deletions i-bem/__json/_async/i-bem__json_async_yes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Processing BEM.JSON.decl asynchronously
*
* @name BEM.JSON
*/
(function (BEM) {

/**
* Wait for resume before build inside block
*/
BEM.JSON._ctx.prototype.wait = function () {
this._threads = this._threads ? this._threads + 1 : 1;
if (this._globalThread) {
this._globalThread.count++;
} else {
throw new Error('Cant wait in synchronous build');
}
};

BEM.JSON._ctx.prototype._buildBemSync = BEM.JSON._ctx.prototype._buildBem;

BEM.JSON._ctx.prototype._buildBem = function () {
if (this._threads === 0) {
this._buildBemSync();
}
}

/**
* Resume building blocks
*/
BEM.JSON._ctx.prototype.resume = function () {
this._threads = Number(this._threads) - 1;
if (this._globalThread) {
this._globalThread.count--;
} else {
throw new Error('Cant resume in synchronous build');
}
this._buildBem();
if(this._globalThread.count === 0) {
this._globalThread.callback();
}
};

BEM.JSON._ctx.prototype._buildWithNewCtx = function (params, pos, siblingsCount, currBlock, tParams) {
var ctx = new BEM.JSON._ctx(
params,
pos,
siblingsCount,
currBlock,
tParams
);
ctx._globalThread = this._globalThread;
ctx._threads = 0;
return ctx.build();
};


/**
* Applies declarations to bemjson asynchronously
*
* @param {Object} param bemjson object
* @param {Function} callback(resultParams) fires after all tree finished
* @param {Function} callback().resultParams resulting bemjson object
*/
BEM.JSON.buildAsync = function (params, callback) {
var resultParams,
thread = {
count: 0,
callback: function () {
callback(resultParams);
}
},
ctx = new BEM.JSON._ctx(params);
ctx._globalThread = thread;
ctx._threads = 0;
resultParams = ctx.build();
if (thread.count === 0) {
thread.callback();
}
};

/**
* Applies declarations to bemjson synchronously
*
* @param {Object} param bemjson object
* @return {Object} bemjson object
*/
BEM.JSON.build = function (params) {
var ctx = new BEM.JSON._ctx(params);
ctx._threads = 0;
return ctx.build();
};

}(BEM));
229 changes: 229 additions & 0 deletions i-bem/__json/_async/i-bem__json_async_yes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
BEM.TEST.decl({block: 'i-bem', elem: 'json', modName: 'async', modVal: 'yes'}, function () {
it('declaration', function () {
expect(BEM.JSON.buildAsync).toBeDefined();
});

it('process sync bemjson', function () {
var json;

BEM.JSON.decl('b-test', {
onBlock: function (ctx) {
ctx.content({elem: 'item'});
},
onElem: {
'item': function (ctx) {
ctx.content('test string');
}
}
});

BEM.JSON.buildAsync({block: 'b-test'}, function (jsonParam) {
json = jsonParam;
});
waitsFor(function () {
return json;
}, 'json never builded', 1000);

runs(function () {
expect(json).toBeDefined();
expect(json.block).toBe('b-test');
expect(json.content).toBeDefined();
expect(json.content.elem).toBeDefined();
expect(json.content.elem).toBe('item');
expect(json.content.content).toBe('test string');
});

});

it('process async bemjson', function () {
var json;

BEM.JSON.decl({name:'b-test', modName: 'test', modVal: 'async'}, {
onBlock: function (ctx) {
ctx.wait();
setTimeout(function () {
ctx.content('async content', true);
ctx.resume();
}, 100);
}
});

BEM.JSON.buildAsync({block: 'b-test', mods: {test: 'async'}}, function (jsonParam) {
json = jsonParam;
});

waitsFor(function () {
return json;
}, 'json never builded', 1000);

runs(function () {
expect(json).toBeDefined();
expect(json.content).toBe('async content');
});

});

it('process async multiple elems', function () {
var json;

BEM.JSON.decl({name:'b-test', modName: 'test', modVal: 'multiple-elems'}, {
onBlock: function (ctx) {
ctx.content([
{elem: 'item-sync'},
{elem: 'item-async', timeout: 100},
{elem: 'item-async', timeout: 200, mods: {'async-param': 'yes'}}
], true);
},
onElem: {
'item-sync': function (ctx) {
ctx.content('item-sync');
},
'item-async': function (ctx) {
ctx.wait();
setTimeout(function () {
ctx.content('item-async');
ctx.resume();
}, ctx.param('timeout'));
if (ctx.mod('async-param') === 'yes') {
ctx.wait();
setTimeout(function () {
ctx.param('async-param', 'yes');
ctx.resume();
}, ctx.param('timeout'));
}
}
}
});

BEM.JSON.buildAsync({block: 'b-test', mods: {test: 'multiple-elems'}}, function (jsonParam) {
json = jsonParam;
});

waitsFor(function () {
return json;
}, 'json never builded', 1000);

runs(function () {
expect(json).toBeDefined();
expect(json.content).toBeDefined();
expect(json.content[0]).toBeDefined();
expect(json.content[0].content).toBe('item-sync');
expect(json.content[1]).toBeDefined();
expect(json.content[1].content).toBe('item-async');
expect(json.content[2]).toBeDefined();
expect(json.content[2].content).toBe('item-async');
expect(json.content[2]['async-param']).toBe('yes');
expect(typeof json.content[0]['async-param']).toBe('undefined');
expect(typeof json.content[1]['async-param']).toBe('undefined');
});

});

it('process async multiple elems', function () {
var json;

BEM.JSON.decl({name:'b-test', modName: 'test', modVal: 'multiple-elems'}, {
onBlock: function (ctx) {
ctx.content([
{elem: 'item-sync'},
{elem: 'item-async', timeout: 100},
{elem: 'item-async', timeout: 200, mods: {'async-param': 'yes'}}
], true);
},
onElem: {
'item-sync': function (ctx) {
ctx.content('item-sync');
},
'item-async': function (ctx) {
ctx.wait();
setTimeout(function () {
ctx.content('item-async');
ctx.resume();
}, ctx.param('timeout'));
if (ctx.mod('async-param') === 'yes') {
ctx.wait();
setTimeout(function () {
ctx.param('async-param', 'yes');
ctx.resume();
}, ctx.param('timeout'));
}
}
}
});

BEM.JSON.buildAsync({block: 'b-test', mods: {test: 'multiple-elems'}}, function (jsonParam) {
json = jsonParam;
});

waitsFor(function () {
return json;
}, 'json never builded', 1000);

runs(function () {
expect(json).toBeDefined();
expect(json.content).toBeDefined();
expect(json.content[0]).toBeDefined();
expect(json.content[0].content).toBe('item-sync');
expect(json.content[1]).toBeDefined();
expect(json.content[1].content).toBe('item-async');
expect(json.content[2]).toBeDefined();
expect(json.content[2].content).toBe('item-async');
expect(json.content[2]['async-param']).toBe('yes');
expect(typeof json.content[0]['async-param']).toBe('undefined');
expect(typeof json.content[1]['async-param']).toBe('undefined');
});

});

it('process async for nested blocks', function () {
var json;

BEM.JSON.decl({name:'b-test', modName: 'test', modVal: 'nested-blocks'}, {
onBlock: function (ctx) {
ctx.content({elem: 'item'}, true);
},
onElem: {
'item': function (ctx) {
ctx.wait();
setTimeout(function () {
ctx.content({block: 'b-test', mods: {nested: 'yes'}}, true)
ctx.resume();
}, 100);
},
}
});

BEM.JSON.decl({name:'b-test', modName: 'nested', modVal: 'yes'}, {
onBlock: function (ctx) {
ctx.content({elem: 'item'}, true);
},
onElem: {
'item': function (ctx) {
ctx.wait();
setTimeout(function () {
ctx.content('async-content', true);
ctx.resume();
}, 100);
},
}
});

BEM.JSON.buildAsync({block: 'b-test', mods: {test: 'nested-blocks'}}, function (jsonParam) {
json = jsonParam;
});

waitsFor(function () {
return json;
}, 'json never builded', 1000);

runs(function () {
expect(json).toBeDefined();
expect(json.content).toBeDefined();
expect(json.content.content).toBeDefined();
expect(json.content.content.content).toBeDefined();
expect(json.content.content.content.content).toBe('async-content');
});

});

});
Loading

0 comments on commit 516ea68

Please sign in to comment.