Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从承诺中的回调中检索数据?_Javascript_Node.js_Promise_Bluebird_Es6 Promise - Fatal编程技术网

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-不要错过我刚才所做的编辑,以修复更多的问题。