从承诺中的callback中检索数据?
我现在有以下一段代码:
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,其数据被返回的是一个callback函数。
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);
但是由于原因,只有前两个是按顺序执行的,而第三个是在读完之后随机执行的。 任何想法,我在这里做错了吗?
由于您使用的是蓝鸟,因此您可以使用.forEach()
来replace.forEach()
循环,并且它会按顺序遍历数组,等待每个asynchronous操作完成后再执行下一个。 结果将是一个承诺谁解决的价值是一系列的结果。 当涉及到asynchronous操作时,还应该停止在更高范围内声明局部variables。 在最近的范围内声明它们是实用的,在这种情况下是它们被使用的范围。
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()
进行顺序asynchronous操作。 - 从
Promise.mapSeries()
返回承诺,所以它与预先约定链接。 - 将variables声明移动到本地作用域中,以避免不同的asynchronous操作改变共享variables。
- logging之后,Rethrow
.catch()
错误,所以拒绝传播 -
return perfData
,使其成为parsing值,并在结果数组中可用。