[英]Return when first promise resolves
我在數組中有一堆文件名,並且想讀取存在的第一個文件的內容。 它們是配置文件,因此順序是確定性很重要,因此我不能使用.race()
。 我下面的版本按順序映射每個文件,嘗試加載它,如果加載成功,則調用resolve。
以下是此實現的幾個問題:
resolve(...)
實際上並不會退出循環,因此該程序即使在不需要時也會打開列表中的每個文件。 this is required to reject when we don't receive any files
拒絕的條件),看起來像是黑客。 但是,如果不在這里,那么承諾就永遠不會被拒絕。 有沒有更好的方法來構造此結構? 我可能只用一個Promise.filter
調用就可以做到這Promise.filter
,但是如果不需要的話,我不想查詢每個文件。
謝謝
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var _ = require('lodash');
new Promise((resolve, reject) => {
// Resolve with the first of the files below that exists
return Promise.mapSeries(
['./file_that_doesntexist.json', '../file_that_might_exist.json', './file_that_doesnt_exist_either.json', '../file_that_exists.json']
, (filename) => fs.readFileAsync(filename, 'utf-8')
.then(file => {
resolve([filename, file]);
return true;
})
.catch(_.stubFalse)
)
.then(files => { // this is required to reject when we don't receive any files
if(!files.some(x => x))
reject('did not receive any files');
});
})
.then(function([filename, configFile]) {
// do something with filename and configFile
})
.catch(function(err) {
console.error(err)
})
如果要順序迭代,只需使用遞歸方法:
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
function readFirstOf(filenames)
if (!filenames.length)
return Promise.reject(new Error('did not receive any files'));
return fs.readFileAsync(filenames[0], 'utf-8')
.then(file =>
[filenames[0], file]
, err =>
readFirstOf(filenames.slice(1))
);
}
readFirstOf(['./file_that_doesntexist.json', '../file_that_might_exist.json', './file_that_doesnt_exist_either.json', '../file_that_exists.json'])
.then(function([filename, configFile]) {
// do something with filename and configFile
})
.catch(function(err) {
console.error(err)
})
如果要嘗試並行讀取所有內容並選擇列表中的第一個成功對象,則可以使用Promise.map
+ Promise.map
.reflect()
然后僅過濾結果(例如,通過_.find
)。
這可以通過遞歸來實現,也可以通過使用Array#reduce()構建catch
鏈來實現:
var paths = ['./file_that_doesntexist.json', '../file_that_might_exist.json', './file_that_doesnt_exist_either.json', '../file_that_exists.json'];
// Resolve with the first of the files below that exists
paths.reduce(function(promise, path) {
return promise.catch(function(error) {
return fs.readFileAsync(path, 'utf-8').then(file => [path, file]);
});
}, Promise.reject())
.then(function([filename, configFile]) {
// do something with filename and configFile
})
.catch(function(err) {
console.error('did not receive any files', err);
});
捕獲鏈確保每次fs.readFileAsync(path, 'utf-8')
失敗時,都嘗試下一個路徑。
第一個成功的fs.readFileAsync(path, 'utf-8')
將進入.then(function([filename, configFile]) {...}
。
完全失敗將落入.catch(function(err) {...}
。
有這種駭人聽聞的方法可以巧妙地解決這個問題。 您可以像這樣invert
承諾。
var invert = pr => pr.then(v => Promise.reject(v), x => Promise.resolve(x));
實際上,當與Promise.all()
一起使用時, Promise.all()
可以通過忽略被拒絕的對象來獲得第一個解決承諾,因此非常方便。 我的意思是倒立時,拒絕了所有的承諾(解決)可能會被忽視,而第一解析(拒絕)一個被在抓.catch()
階段Promise.all()
涼..!
看這個;
var invert = pr => pr.then(v => Promise.reject(v), x => Promise.resolve(x)), promises = [Promise.reject("No such file"), Promise.reject("No such file either"), Promise.resolve("This is the first existing files content"), Promise.reject("Yet another missing file"), Promise.resolve("Another file content here..!")]; Promise.all(promises.map(pr => invert(pr))) .catch(v => console.log(`First successfully resolving promise is: ${v}`));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.