Javascript 从承诺中的回调中检索数据?
我现在有以下代码:Javascript 从承诺中的回调中检索数据?,javascript,node.js,promise,bluebird,es6-promise,Javascript,Node.js,Promise,Bluebird,Es6 Promise,我现在有以下代码: const Promise = require('bluebird'); const readFile = Promise.promisify(fs.readFile); recordPerfMetrics: function(url) { var self = this; var perf, loadTime, domInteractive, firstPaint; var perfData = {}; readFile('u
const Promise = require('bluebird');
const readFile = Promise.promisify(fs.readFile);
recordPerfMetrics: function(url) {
var self = this;
var perf, loadTime, domInteractive, firstPaint;
var perfData = {};
readFile('urls.txt', 'UTF-8').then(function (urls, err) {
if (err) {
return console.log(err);
}
var urls = urls.split("\n");
urls.shift();
urls.forEach(function(url) {
console.log(url);
self.getStats(url).then(function(data) {
data = data[0];
loadTime = (data.loadEventEnd - data.navigationStart)/1000 + ' sec';
firstPaint = data.firstPaint;
domInteractive = (data.domInteractive - data.navigationStart)/1000 + ' sec';
perfData = {
'URL' : url,
'firstPaint' : firstPaint,
'loadTime' : loadTime,
'domInteractive' : domInteractive
};
console.log(perfData);
}).catch(function(error) {
console.log(error);
});
});
// console.log(colors.magenta("Starting to record performance metrics for " + url));
// this.storePerfMetrics();
});
},
getStats: function(url) {
return new Promise(function(resolve, reject){
console.log("Getting data for url: ",url);
browserPerf(url, function(error, data) {
console.log("inside browserPerf", url);
if (!error) {
resolve(data);
} else {
reject(error);
}
}, {
selenium: 'http://localhost:4444/wd/hub',
browsers: ['chrome']
});
});
},
这基本上是从文件中读取URL,然后调用browserPerf函数,其返回的数据位于回调函数中
console.log(“获取url的数据:”,url)
的顺序与文件中存储的URL的顺序相同
但是console.log(“insidebrowserperf”,url)代码>与预期的不一样
我希望URL的顺序是:
console.log(url);
console.log("Getting data for url: ",url);
console.log("inside browserPerf", url);
但出于某种原因,只有前两个命令是按顺序执行的,而第三个命令是在读取所有命令后随机触发的。
知道我做错了什么吗?因为您使用的是Bluebird,所以可以将.forEach()
循环替换为Promise.mapSeries()
,它将依次遍历您的数组,等待每个异步操作完成,然后再执行下一个操作。结果将是一个承诺,谁的解析值是一个结果数组。当涉及异步操作时,还应该停止在更高的范围内声明局部变量。在最近的实际范围内声明它们,在本例中,实际范围就是使用它们的范围
const Promise = require('bluebird');
const readFile = Promise.promisify(fs.readFile);
recordPerfMetrics: function() {
var self = this;
return readFile('urls.txt', 'UTF-8').then(function (urls) {
var urls = urls.split("\n");
urls.shift();
return Promise.mapSeries(urls, function(url) {
console.log(url);
return self.getStats(url).then(function(data) {
data = data[0];
let loadTime = (data.loadEventEnd - data.navigationStart)/1000 + ' sec';
let firstPaint = data.firstPaint;
let domInteractive = (data.domInteractive - data.navigationStart)/1000 + ' sec';
let perfData = {
'URL' : url,
'firstPaint' : firstPaint,
'loadTime' : loadTime,
'domInteractive' : domInteractive
};
console.log(perfData);
return perfData;
}).catch(function(error) {
console.log(error);
throw error; // keep the promise rejected
});
});
// console.log(colors.magenta("Starting to record performance metrics for " + url));
// this.storePerfMetrics();
});
},
getStats: function(url) {
return new Promise(function(resolve, reject){
console.log("Getting data for url: ",url);
browserPerf(url, function(error, data) {
console.log("inside browserPerf", url);
if (!error) {
resolve(data);
} else {
reject(error);
}
}, {
selenium: 'http://localhost:4444/wd/hub',
browsers: ['chrome']
});
});
},
您可以这样使用它:
obj.recordPerfMetrics().then(function(results) {
// process results array here (array of perfData objects)
}).catch(function(err) {
// error here
});
更改摘要:
从recordPefMetrics返回承诺,以便调用者可以获取数据
对于顺序异步操作,请使用Promise.mapSeries()
而不是.forEach()
从promise.mapSeries()
返回promise,因此它与先前的promise链接在一起
将变量声明移动到局部范围中,这样就不会改变对共享变量的不同异步操作
记录后重试.catch()
错误,因此拒绝会传播
返回perfData
,使其成为解析值并在结果数组中可用
您的.forEach()
循环同步运行。它内部的异步操作都是一次启动的,并将在任何时候完成,而不考虑.forEach()
循环。如果要在完成多个承诺时进行协调,可以将它们排序为一个接一个地运行,或者使用Promise.all()
在它们全部完成时获得通知。还有数百个其他问题/答案解释了如何执行其中一个选项。此外,由于您使用的是Bluebird,请尝试使用Bluebird的映射函数替换。forEach()
,它还有一个很好的并发选项。你是想一个接一个地排列你的URL,还是想并行地获取所有URL的统计信息,然后知道它们何时都准备好了?@jfriend00:我正在尝试对URL进行排序,并在一个URL准备好后获取统计信息,然后是下一个,然后是下一个,依此类推。。因此,如果我们有:www.abc.com、www.xyz.com、www.aaa.com,我想要abc、xyz和aaa的统计数据。@jp310-不要错过我刚才所做的编辑,以修复更多的问题。