从承诺中的回调中检索数据?
Retrieve data from a callback thats in a 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('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("Getting data for url: ",url);
与存储在文件中的 url 的顺序相同,
但是 console.log("inside browserPerf", url);
与预期的不一样。
我希望 url 的顺序是:
console.log(url);
console.log("Getting data for url: ",url);
console.log("inside browserPerf", url);
但由于原因只有前两个按顺序执行,而第三个在所有读取后随机触发。
知道我在这里做错了什么吗?
由于您使用的是 Bluebird,您可以将 .forEach()
循环替换为 Promise.mapSeries()
,它将依次遍历您的数组,等待每个异步操作完成,然后再执行下一个。结果将是一个承诺 who's resolved value is a array of results。当涉及异步操作时,您还应该停止在更高范围内声明局部变量。在最近的实际范围内声明它们,在本例中是它们的使用范围。
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
});
更改摘要:
- Return 来自 recordPefMetrics 的承诺,因此调用者可以获得数据
- 使用
Promise.mapSeries()
而不是 .forEach()
进行顺序异步操作。
- Return 来自
Promise.mapSeries()
的承诺,因此它与先前的承诺链接在一起。
- 将变量声明移动到本地范围内,这样就不会改变不同的异步操作对共享变量的影响。
- 记录后重新抛出
.catch()
错误,以便拒绝传播
return perfData
所以它成为解析值并在结果数组中可用。
我现在有以下代码:
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("Getting data for url: ",url);
与存储在文件中的 url 的顺序相同,
但是 console.log("inside browserPerf", url);
与预期的不一样。
我希望 url 的顺序是:
console.log(url);
console.log("Getting data for url: ",url);
console.log("inside browserPerf", url);
但由于原因只有前两个按顺序执行,而第三个在所有读取后随机触发。 知道我在这里做错了什么吗?
由于您使用的是 Bluebird,您可以将 .forEach()
循环替换为 Promise.mapSeries()
,它将依次遍历您的数组,等待每个异步操作完成,然后再执行下一个。结果将是一个承诺 who's resolved value is a array of results。当涉及异步操作时,您还应该停止在更高范围内声明局部变量。在最近的实际范围内声明它们,在本例中是它们的使用范围。
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
});
更改摘要:
- Return 来自 recordPefMetrics 的承诺,因此调用者可以获得数据
- 使用
Promise.mapSeries()
而不是.forEach()
进行顺序异步操作。 - Return 来自
Promise.mapSeries()
的承诺,因此它与先前的承诺链接在一起。 - 将变量声明移动到本地范围内,这样就不会改变不同的异步操作对共享变量的影响。
- 记录后重新抛出
.catch()
错误,以便拒绝传播 return perfData
所以它成为解析值并在结果数组中可用。