如何重用承诺?

Pra*_*aid 5 javascript node.js promise bluebird

我试图在这里重用从 promise 返回的数据。但是,问题是,在第一次调用checkPromisefunction 之后,它立即调用第二个函数,并且第一个函数的 promise 没有实现,因此它永远不会返回任何数据,因此它永远不会进入 if 子句。我如何重用承诺?

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);
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 5

您可能有时间问题。你的apiCall()函数是异步的。这意味着它会在稍后完成。因此,每次您调用 时checkPromise(),您所做的只是开始一个请求,并在稍后的某个时间完成。因此,您第一次调用它并启动一个请求(尚未完成)。然后,您的下一次调用checkPromise()被调用,它会if在第一次调用完成之前进行检查。因此,它还没有在缓存中找到任何东西。

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

如果您真的想等到第一个请求完成后再执行第二个请求,那么您将不得不实际构建代码来做到这一点。您需要自己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)) {   
        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);
});
Run Code Online (Sandbox Code Playgroud)

重大变化:

  1. 返回由返回的承诺request()而不是创建另一个承诺。
  2. 更改checkPromise()使其始终返回一个承诺,无论该值是否在缓存中找到,因此调用代码始终可以始终如一地工作。
  3. 对两个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
});
Run Code Online (Sandbox Code Playgroud)