如何重用承诺?
How to reuse promises?
我正在尝试重用从 promise 返回的数据。但是,问题是,在第一次调用 checkPromise
函数之后,它立即调用了第二个函数,而第一个函数的承诺没有实现,所以它从来没有 returns 任何数据,因此它从不进入 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);
您可能遇到了时间问题。您的 apiCall()
函数是异步的。这意味着它会在稍后的某个时间完成。因此,每次调用 checkPromise()
时,您所做的只是启动一个请求,它会在稍后完成。因此,您第一次调用它并启动一个请求(尚未完成)。然后,将调用您对 checkPromise()
的下一次调用,并在第一次调用完成之前进行 if
检查。因此,它尚未在缓存中找到任何内容。
您的代码是运行两个并行请求,而不是一个接一个。
如果您真的想等到第一个请求完成后再执行第二个请求,那么您将不得不实际构建代码来执行此操作。您需要使 checkPromise()
return 本身成为一个承诺,以便使用它的代码可以知道它实际完成的时间,以便在完成后执行某些操作。
仅供参考,我在您的代码中没有看到任何与重用承诺相关的内容(这是您不能做的事情,因为它们是一次性对象)。
这是一种可能的实现方式:
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);
});
重大变化:
- Return 由
request()
编辑的承诺 return 而不是创建另一个承诺。
- 更改
checkPromise()
使其始终 return 承诺是否在缓存中找到该值,以便调用代码始终一致地工作。
- 对两个
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
});
您的代码几乎没有问题,首先在 apiCall
中,您正在执行承诺蚂蚁模式(不需要新的承诺),其次您的 checkPromise 正在执行同步操作,因此它必须 return一个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 request(url).spread(function(response, body) {
return body;
}).catch(function(err) {
console.error(err);
throw err;
});
}
function checkPromise(url) {
var promise = Promise.resolve();
if(obj.hasOwnProperty(url)) {
var rp = obj[url];
//do something
}
else {
return apiCall(url).then(function(result) {
obj[url] = result;
//do something
});
}
return promise;
}
checkPromise(url).then(function(){
return checkPromise(url);
});
考虑到您将结果全局存储在 'obj[url]'
中的方式,这可能是最容易做到的
function checkPromise(url) {
if (!obj[url]) obj[url] = apiCall(url);
obj[url].then(function(result) {
//do something
});
}
基本上是发出请求,如果它还没有开始,则在加载结果时附加一个侦听器到 promise。
Here 是最简单的示例,说明如果对某物有多个类似请求(例如缓存检查)
,如何防止多次 API 调用
var _cache = {
state: 0,
result: undefined,
getData: function(){
log('state: ' + this.state);
if(this.state === 0 ){ // not started
this.state = 1; // pending
this.promise = new Promise(function(resolve, reject) {
return (apiCall().then(data => { _cache.result = data; _cache.state = 2; resolve(_cache.result) }));
})
return this.promise;
}
else if(this.state === 1){ // pending
return this.promise;
}
else if(this.state === 2){// resolved
return Promise.resolve(this.result);
}
},
};
模拟api通话
function apiCall(){
return new Promise(function(resolve, reject) {
log('in promise')
setTimeout(() => {
log('promise resolving')
resolve(1);
}, 1000);
})
}
同时发出请求。
_cache.getData().then(result => { log('first call outer: ' + result);
_cache.getData().then(result => { log('first call inner: ' + result); });
});
_cache.getData().then(result => { log('second call outer: ' + result);
_cache.getData().then(result => { log('second call inner: ' + result); });
});
只打了一个 API 电话。所有其他人将等待完成或使用已解决的结果(如果已经完成)。
我正在尝试重用从 promise 返回的数据。但是,问题是,在第一次调用 checkPromise
函数之后,它立即调用了第二个函数,而第一个函数的承诺没有实现,所以它从来没有 returns 任何数据,因此它从不进入 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);
您可能遇到了时间问题。您的 apiCall()
函数是异步的。这意味着它会在稍后的某个时间完成。因此,每次调用 checkPromise()
时,您所做的只是启动一个请求,它会在稍后完成。因此,您第一次调用它并启动一个请求(尚未完成)。然后,将调用您对 checkPromise()
的下一次调用,并在第一次调用完成之前进行 if
检查。因此,它尚未在缓存中找到任何内容。
您的代码是运行两个并行请求,而不是一个接一个。
如果您真的想等到第一个请求完成后再执行第二个请求,那么您将不得不实际构建代码来执行此操作。您需要使 checkPromise()
return 本身成为一个承诺,以便使用它的代码可以知道它实际完成的时间,以便在完成后执行某些操作。
仅供参考,我在您的代码中没有看到任何与重用承诺相关的内容(这是您不能做的事情,因为它们是一次性对象)。
这是一种可能的实现方式:
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);
});
重大变化:
- Return 由
request()
编辑的承诺 return 而不是创建另一个承诺。 - 更改
checkPromise()
使其始终 return 承诺是否在缓存中找到该值,以便调用代码始终一致地工作。 - 对两个
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
});
您的代码几乎没有问题,首先在 apiCall
中,您正在执行承诺蚂蚁模式(不需要新的承诺),其次您的 checkPromise 正在执行同步操作,因此它必须 return一个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 request(url).spread(function(response, body) {
return body;
}).catch(function(err) {
console.error(err);
throw err;
});
}
function checkPromise(url) {
var promise = Promise.resolve();
if(obj.hasOwnProperty(url)) {
var rp = obj[url];
//do something
}
else {
return apiCall(url).then(function(result) {
obj[url] = result;
//do something
});
}
return promise;
}
checkPromise(url).then(function(){
return checkPromise(url);
});
考虑到您将结果全局存储在 'obj[url]'
中的方式,这可能是最容易做到的
function checkPromise(url) {
if (!obj[url]) obj[url] = apiCall(url);
obj[url].then(function(result) {
//do something
});
}
基本上是发出请求,如果它还没有开始,则在加载结果时附加一个侦听器到 promise。
Here 是最简单的示例,说明如果对某物有多个类似请求(例如缓存检查)
,如何防止多次 API 调用var _cache = {
state: 0,
result: undefined,
getData: function(){
log('state: ' + this.state);
if(this.state === 0 ){ // not started
this.state = 1; // pending
this.promise = new Promise(function(resolve, reject) {
return (apiCall().then(data => { _cache.result = data; _cache.state = 2; resolve(_cache.result) }));
})
return this.promise;
}
else if(this.state === 1){ // pending
return this.promise;
}
else if(this.state === 2){// resolved
return Promise.resolve(this.result);
}
},
};
模拟api通话
function apiCall(){
return new Promise(function(resolve, reject) {
log('in promise')
setTimeout(() => {
log('promise resolving')
resolve(1);
}, 1000);
})
}
同时发出请求。
_cache.getData().then(result => { log('first call outer: ' + result);
_cache.getData().then(result => { log('first call inner: ' + result); });
});
_cache.getData().then(result => { log('second call outer: ' + result);
_cache.getData().then(result => { log('second call inner: ' + result); });
});
只打了一个 API 电话。所有其他人将等待完成或使用已解决的结果(如果已经完成)。