第一个承诺解决后返回 [英] Return when first promise resolves

查看:78
本文介绍了第一个承诺解决后返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在数组中有一堆文件名,并且想读取存在的第一个文件的内容.它们是配置文件,因此顺序是确定性很重要,因此我不能使用 .race().我下面的版本按顺序映射每个文件,尝试加载它,如果加载成功,则调用resolve.

I have a bunch of file names in an array, and would like to read the contents of the first of the files that exists. They're config files, so it's important that the order is deterministic, so I can't use .race(). The version I have below maps over each file in order, tries to load it, and if it loads successfully, calls resolve.

此实现存在两个问题:

  1. 调用 resolve(...)实际上并不会退出循环,因此该程序即使在不需要时也会打开列表中的每个文件.
  2. 拒绝条件(在,当我们没有收到任何文件时,必须拒绝此条件)看起来像是黑客.但是,如果不在这里,那么承诺就永远不会被拒绝.
  3. 解析代码似乎可疑地像一个承诺反模式.
  1. Calling resolve(...) doesn't actually exit the loop, so the program opens every file in the list, even when doesn't need to.
  2. The rejection condition (at this is required to reject when we don't receive any files) seems like a hack. However, if it's not here, the promise is never rejected.
  3. The resolution code seems suspiciously like a promise anti-pattern.

有没有更好的方法来构建此结构?我可能只需一个 Promise.filter 调用就可以完成此操作,但是如果不需要,我不想查询每个文件.

Are there any better ways to do structure this? I could probably do it with a single Promise.filter call, but I don't want to query every file if I don't need to.

谢谢

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

推荐答案

这可以通过递归来实现,也可以通过使用Array#reduce()构建 catch 链来实现:

This can be achieved by recursion but also by building a catch chain using Array#reduce():

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')失败时,都会尝试下一条路径.

The catch chain ensures that every time fs.readFileAsync(path, 'utf-8') fails, the next path is tried.

第一个成功的 fs.readFileAsync(path,'utf-8')将进入 .then(function([filename,configFile]){...} .

总故障将落入 .catch(function(err){...} .

这篇关于第一个承诺解决后返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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