从承诺中的回调中检索数据? [英] Retrieve data from a callback thats in a promise?

查看:46
本文介绍了从承诺中的回调中检索数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在有以下代码:

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,其返回的数据在回调函数中.

This is basically reading urls from a file and then calling a function browserPerf whose data being returned is in a callback function.

console.log("Getting data for url: ",url);的顺序与文件中存储的网址的顺序相同,

The console.log("Getting data for url: ",url); is in the same order as the urls that are stored in the file,

,但console.log("inside browserPerf", url);与期望的合词不同.

but the console.log("inside browserPerf", url); is not conjunction as the same and as expected.

我希望这些网址的顺序为:

I expect the order of the urls to be:

console.log(url);   
console.log("Getting data for url: ",url);
console.log("inside browserPerf", url);

但是出于某种原因,只有前两个按顺序执行,但是在全部读取之后会随机触发第三个. 知道我在这里做错了吗?

But for reason only the first two are executed in order but the third one is fired randomly after all are being read. Any idea what i am doing wrong here?

推荐答案

由于使用的是Bluebird,因此可以将.forEach()循环替换为Promise.mapSeries(),它将依次遍历数组,等待每个异步操作完成在进行下一个之前.结果将是一个诺言,谁的解决价值是一系列结果.当您涉及异步操作时,还应该停止在更高范围内声明局部变量.在最实际的范围内声明它们,在这种情况下,即为它们的使用范围.

Since you are using Bluebird, you can replace your .forEach() loop with Promise.mapSeries() and it will sequentially walk through your array waiting for each async operation to finish before doing the next one. The result will be a promise who's resolved value is an array of results. You also should stop declaring local variables in a higher scope when you have async operations involved. Declare them in the nearest scope practical which, in this case is the scope in which they are used.

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
});

更改摘要:

  1. 从recordPefMetrics返回承诺,以便调用者可以获取数据
  2. 使用Promise.mapSeries()而不是.forEach()进行顺序异步操作.
  3. Promise.mapSeries()返回承诺,因此它与先前的承诺链接在一起.
  4. 将变量声明移至本地范围,因此不会对踩踏共享变量的不同异步操作进行任何更改.
  5. 记录后
  6. 重新抛出.catch()错误,以便拒绝传播
  7. return perfData,因此它成为已解析的值,并且可以在结果数组中使用.
  1. Return promise from recordPefMetrics so caller can get data
  2. Use Promise.mapSeries() instead of .forEach() for sequential async operations.
  3. Return promise from Promise.mapSeries() so it is chained with prior promise.
  4. Move variable declarations into local scope so there is no change of different async operations stomping on shared variables.
  5. Rethrow .catch() error after logging so the reject propagates
  6. return perfData so it becomes the resolved value and is available in results array.

这篇关于从承诺中的回调中检索数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆