我正在尝试重用从promise返回的数据。但是,问题是,在第一次调用checkPromise函数之后,它立即调用了第二个函数,并且没有满足第一个函数的 promise ,因此它从不返回任何数据,因此也从不输入if子句。我如何重用 promise ?

var Promise = require('bluebird');
var request = Promise.promisify(require("request"));


var url = 'http://www.google.com';
var obj = new Object;

function apiCall(url) {
    return new Promise(function (resolve, reject) {

        request(url).spread(function(response, body) {
            return resolve(body);
        }).catch(function(err) {
            console.error(err);
            return reject(err);
        });

    });
}

function checkPromise(url) {
    if(obj.hasOwnProperty(url)) {
        var rp = obj[url];
        //do something
    }
    else {
        apiCall(url).then(function(result) {
            obj[url] = result;
            //do something
        });
    }
}

checkPromise(url);
checkPromise(url);

最佳答案

您可能有计时问题。您的apiCall()函数是异步的。这意味着它会在以后的某个时间完成。这样,每次调用checkPromise()时,您所做的就是启动请求,并在以后的某个时间完成。因此,您第一次调用它,它启动了一个请求(尚未完成)。然后,您的下一个对checkPromise()的调用将被调用,并在第一个调用完成之前进行if检查。因此,它尚未在缓存中找到任何内容。

您的代码正在并行运行两个请求,而不是一个接一个。

如果您实际上要等到第一个请求完成后再执行第二个请求,那么您将必须实际构造代码来执行此操作。您需要使checkPromise()本身返回一个Promise,以便可以在实际完成时知道使用它的代码,以便在完成后执行某些操作。

仅供引用,我在您的代码中看不到任何与重用Promise相关的东西(这是您无法完成的事情,因为它们是一次性的对象)。

这是一种可能的实现:

var Promise = require('bluebird');
var request = Promise.promisify(require("request"));

var url = 'http://www.google.com';
var obj = {};

function apiCall(url) {
    return request(url).spread(function(response, body) {
        return body;
    });
}

function checkPromise(url) {
    if(obj.hasOwnProperty(url)) {
        var rp = obj[url];
        //do something
        return Promise.resolve(rp);
    }
    else {
        return apiCall(url).then(function(result) {
            obj[url] = result;
            //do something
            return result;
        });
    }
}

checkPromise(url).then(function() {
    checkPromise(url);
});

重大更改:
  • 返回request()返回的promise,而不是创建另一个promise。
  • 更改checkPromise(),以便无论是否在缓存中找到该值,它始终会返回一个保证,因此调用代码始终可以始终如一地工作。
  • 对两个checkPromise()调用进行排序,以便第一个调用可以在第二个调用执行之前完成。


  • 如果您感兴趣的结果已经被加载,则非常不同的方法是实际等待缓存。可以这样完成:
    var Promise = require('bluebird');
    var request = Promise.promisify(require("request"));
    
    var url = 'http://www.google.com';
    var obj = {};
    
    function apiCall(url) {
        return request(url).spread(function(response, body) {
            return body;
        });
    }
    
    function checkPromise(url) {
        if(obj.hasOwnProperty(url)) {
            // If it's a promise object in the cache, then loading
            // If it's a value, then the value is already available
            // Either way, we wrap it in a promise and return that
            return Promise.resolve(obj[url]);
        } else {
            var p = apiCall(url).then(function(result) {
                obj[url] = result;
                //do something
                return result;
            });
            obj[url] = p;
            return p;
        }
    }
    
    checkPromise(url).then(function(result) {
        // use result
    });
    
    checkPromise(url).then(function(result) {
        // use result
    });
    

    09-25 18:26