在承诺链中等待 DOM 元素中的突变
Wait in a promise chain for a mutation in a DOM element
我正在 Node.js 中制作某种网络抓取工具,它会拍摄出现在带有 PhantomJS.
的网站上的地图照片
但是,一旦打开页面,loading 消息就会出现在地图应该出现的位置。地图准备就绪后,消息消失 (visibility: hidden
) 并显示地图。
因此,在 #loader
为 hidden
之前,我无法调用 page.render()
(否则我会得到加载消息的图片,不太酷)。
// ... Open the page
.then(function(content) {
return page.evaluate(function() {
// Wait for #loading to get hidden somehow ...
var clipRect = document.getElementById('map').getBoundingClientRect();
return {
top: clipRect.top,
left: clipRect.left,
width: clipRect.width,
height: clipRect.height
};
});
})
// Render and process the picture ...
我考虑过使用 mutation observer,但找不到使用它的方法,因为我在 承诺链 中并且事件侦听器不会'不能如我所愿
我也尝试经常检查 visibility
属性,直到它被隐藏,正如 here 所解释的,但是 PhantomJS 通过 Node 的控制台报告:
TypeError: null is not an object (evaluating 'child.transform')
此外,我想尽可能避免这种变通方法,因为它们非常 CPU 密集。
关于如何在这种情况下等待 #loader
获得 hidden
有什么想法吗?
感谢phantomjs-node
's mantainer, amir20, so all credit to him. As he explains in this issue我终于解决了这个问题:
waitFor
expects to return a value. But evaluate
returns a Promise
. So that's why it is not working. This is not a problem of the module but rather problem with waitFor
. Since everything is executed asynchronously then you have to wait for the value.
有问题的函数(由他创建)如下:
function waitUntil(asyncTest) {
return new Promise(function(resolve, reject) {
function wait() {
asyncTest().then(function(value) {
if (value === true) {
resolve();
} else {
setTimeout(wait, 100);
}
}).catch(function(e) {
console.log('Error found. Rejecting.', e);
reject();
});
}
wait();
});
}
因此,应用到我的具体例子中,应该这样使用:
waitUtil(function() {
return sitepage.evaluate(function() {
return document.querySelectorAll('#loader').style.visibility == "hidden";
})
}).then(function(){ // #loading is now hidden
return page.evaluate(function() {
var clipRect = document.getElementById('map').getBoundingClientRect();
return {
top: clipRect.top,
left: clipRect.left,
width: clipRect.width,
height: clipRect.height
};
});
})
// Render and process the picture ...
我正在 Node.js 中制作某种网络抓取工具,它会拍摄出现在带有 PhantomJS.
的网站上的地图照片但是,一旦打开页面,loading 消息就会出现在地图应该出现的位置。地图准备就绪后,消息消失 (visibility: hidden
) 并显示地图。
因此,在 #loader
为 hidden
之前,我无法调用 page.render()
(否则我会得到加载消息的图片,不太酷)。
// ... Open the page
.then(function(content) {
return page.evaluate(function() {
// Wait for #loading to get hidden somehow ...
var clipRect = document.getElementById('map').getBoundingClientRect();
return {
top: clipRect.top,
left: clipRect.left,
width: clipRect.width,
height: clipRect.height
};
});
})
// Render and process the picture ...
我考虑过使用 mutation observer,但找不到使用它的方法,因为我在 承诺链 中并且事件侦听器不会'不能如我所愿
我也尝试经常检查 visibility
属性,直到它被隐藏,正如 here 所解释的,但是 PhantomJS 通过 Node 的控制台报告:
TypeError: null is not an object (evaluating 'child.transform')
此外,我想尽可能避免这种变通方法,因为它们非常 CPU 密集。
关于如何在这种情况下等待 #loader
获得 hidden
有什么想法吗?
感谢phantomjs-node
's mantainer, amir20, so all credit to him. As he explains in this issue我终于解决了这个问题:
waitFor
expects to return a value. Butevaluate
returns aPromise
. So that's why it is not working. This is not a problem of the module but rather problem withwaitFor
. Since everything is executed asynchronously then you have to wait for the value.
有问题的函数(由他创建)如下:
function waitUntil(asyncTest) {
return new Promise(function(resolve, reject) {
function wait() {
asyncTest().then(function(value) {
if (value === true) {
resolve();
} else {
setTimeout(wait, 100);
}
}).catch(function(e) {
console.log('Error found. Rejecting.', e);
reject();
});
}
wait();
});
}
因此,应用到我的具体例子中,应该这样使用:
waitUtil(function() {
return sitepage.evaluate(function() {
return document.querySelectorAll('#loader').style.visibility == "hidden";
})
}).then(function(){ // #loading is now hidden
return page.evaluate(function() {
var clipRect = document.getElementById('map').getBoundingClientRect();
return {
top: clipRect.top,
left: clipRect.left,
width: clipRect.width,
height: clipRect.height
};
});
})
// Render and process the picture ...