将递归函数转换为异步CPS实现(javascript) [英] Converting a recursive function into an asynchronous CPS implementation (javascript)
问题描述
function duplicate_step_through_highlighted(element_jq,target_jq,char_cb){
console.log(element_jq);
var contents = element_jq.contents();
(var i = 0; i< contents.length; ++ i){
//如果文本节点,步
if(contents [i] .nodeType === 3 ){
//插入空文本节点
var new_tn = document.createTextNode('');
target_jq.append(new_tn);
//迭代它
var text = contents [i] .nodeValue;
for(var j = 0; j< text.length; j ++){
char_cb(text [j],new_tn);
new_tn.nodeValue + = text [j];
// ***我想要一个异步延迟这里***
}
} else {//类型应该是1:元素
// target_jq获取一个重复的元素插入,复制attrs
var new_elem = $(contents [i] .cloneNode(false))。appendTo(target_jq);
duplicate_step_through_highlighted($(contents [i]),$(new_elem),char_cb);
//然后对新创建的元素执行一个递归调用,如target_jq
//,而现有元素作为element_jq执行。 char_cb通过
}
}
}
正在做的是通过一次重建一个字符来重建HTML元素。有一个很好的理由这样做,我想要它的视觉效果输入。
所以现在没有任何延迟,所以我的元素立即重复。我检查结果是一致的,但是对我来说,我可能需要完全重写功能,以便在插入每个字符后才能够进入异步延迟。
我需要重新编写它,并有一个堆栈来跟踪我在元素中的位置吗?
你可能想看看我最近的一个 answer 或这个较旧的( Demo ),关于如何实现这种效果。
提示:不要将元素复制成新的元素,只需隐藏它们并使其显示为零件。
此外,它可能是除了原生DOM元素,更容易处理jQuery实例。所以是的,重写可能会做:-)而且我认为它也需要一个堆栈。
function animate(elements,回调){
/ * get:要隐藏的元素要显示的数组,回调函数* /
var i = 0;
(function iterate(){
if(i< elements.length){
elements [i] .style.display =block; // show
animateNode元素[i],迭代);
i ++;
} else if(callback)
callback();
})();
function animateNode(element,callback){
var pieces = [];
if(element.nodeType == 1){
while(element.hasChildNodes())
pieces.push(element.removeChild(element.firstChild));
setTimeout(function childStep(){
if(pieces.length){
animateNode(pieces [0],childStep);
element.appendChild(pieces.shift()) ;
} else
callback();
},1000/60);
} else if(element.nodeType == 3){
pieces = element.data.match(/。{0,2} / g); // 2:每帧的字符数
element.data =;
(function addText(){
element.data + = pieces.shift();
setTimeout(pieces.length
?addText
:callback,
1000/60);
})();
}
}
}
animate($(#foo)。children());
如何工作:
-
addText
函数向当前文本节点添加一些字符,并设置自己的超时 - 动画!如果一切都完成,它将调用回调
函数。 -
childStep
在一个子节点上运行动画,并将其自身作为回调,直到没有孩子被留下 - 然后nvokes回调
函数。 - 一起,
animateNode
递归运行在节点树上,按照顺序动画文本节点。 -
iterate
通过将自身作为回调函数调用所有输入元素的函数调用animateNode
(在解除它们之后)。所有输入元素完成后,它将调用外部回调
,作为第二个参数给出animate
。
Here's my function.
function duplicate_step_through_highlighted (element_jq, target_jq, char_cb) {
console.log( element_jq);
var contents = element_jq.contents();
for (var i = 0 ; i < contents.length; ++i) {
// if text node, step
if (contents[i].nodeType === 3) {
// insert empty text node
var new_tn = document.createTextNode('');
target_jq.append(new_tn);
// iterate it
var text = contents[i].nodeValue;
for (var j = 0; j < text.length; j++) {
char_cb(text[j],new_tn);
new_tn.nodeValue += text[j];
// *** I want an async delay here ***
}
} else { // type should be 1: element
// target_jq gets a duplicate element inserted, copying attrs
var new_elem = $(contents[i].cloneNode(false)).appendTo(target_jq);
duplicate_step_through_highlighted($(contents[i]),$(new_elem),char_cb);
// then a recursive call is performed on the newly created element as target_jq
// and the existing one as element_jq. char_cb is passed in
}
}
}
What I'm doing is rebuilding an HTML element by reconstructing it one character at a time. There is a good reason for doing this, I want the visual effect of it getting "typed in".
So right now there are no delays so my element gets duplicated instantly. I have checked that the result is consistent, but it is becoming clear to me that I will probably need to completely re-write the functionality in order for me to be able to put in an asynchronous delay after each character is inserted.
Will I need to re-write it and have a stack to keep track of my position within the elements?
You might want to have a look at my recent answer or this older one (Demo), on how to implement such an effect.
Tip: Don't clone the elements into new ones, just hide them and make them appear part-for-part.
Also, it might be easier not to deal with jQuery instances at all but native DOM elements. So yes, a rewrite might do :-) And I think it does need a stack as well.
function animate(elements, callback) {
/* get: array with hidden elements to be displayes, callback function */
var i = 0;
(function iterate() {
if (i < elements.length) {
elements[i].style.display = "block"; // show
animateNode(elements[i], iterate);
i++;
} else if (callback)
callback();
})();
function animateNode(element, callback) {
var pieces = [];
if (element.nodeType==1) {
while (element.hasChildNodes())
pieces.push(element.removeChild(element.firstChild));
setTimeout(function childStep() {
if (pieces.length) {
animateNode(pieces[0], childStep);
element.appendChild(pieces.shift());
} else
callback();
}, 1000/60);
} else if (element.nodeType==3) {
pieces = element.data.match(/.{0,2}/g); // 2: Number of chars per frame
element.data = "";
(function addText(){
element.data += pieces.shift();
setTimeout(pieces.length
? addText
: callback,
1000/60);
})();
}
}
}
animate($("#foo").children());
How it works:
- The
addText
function adds some character to the current text node, and sets a timeout for itself - animation! In case everything is done, it invokes thecallback
function. childStep
runs the animation on a childnode, and passes itself as the callback until no children are left - then nvokes thecallback
function.- Both together,
animateNode
recursively runs over the node tree and animates the textnodes in thier order. - the
iterate
function callsanimateNode
(after unhinding them) on all input elements, by passing itself as the callback. After all input elements are finished, it invokes the outercallback
which is given as the second argument toanimate
.
这篇关于将递归函数转换为异步CPS实现(javascript)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!