Promise.all():在解决和/或拒绝所有Promise后返回结果

时间:2017-03-08 14:09:49

标签: javascript promise

我遇到了这段代码的问题:

// var env_array = ["env1", "env2", "env3", "env4"];

Promise.all(env_array.map(function(env) {
    return device_get_env(env).catch(function(err) { return err });
})).then(function(data) {
    console.log(data);
    data.forEach(function(entry) {
        console.log(entry.data.connected);
    });
}).catch(function(data) {
    console.log(data);
});


function device_get_env(env) {
    var env = ...;
    var device_id = ...;

    return get_token_data(env, 0).then(function(data) {

        var url_base = ... ;

        return $.ajax({
            url: url_base,
            method: "GET",
            dataType: 'json',
            headers: {Authorization: data.token_type + " " + data.access_token}
        });
    });
}


function get_token_data(env, auth) {
    var client_id = env_tokens[env].client_id;
    var client_secret = env_tokens[env].client_secret;
    var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";

    return $.ajax({
        url: "https://" + env + ".xxxx.com/oauth/token",
        method: "POST",
        data: {
            "client_id": client_id,
            "client_secret": client_secret,
            "audience": audience,
            "grant_type": "client_credentials"
        },
        dataType: 'json'
    });
}

基本上我需要迭代env_array并在我的某些环境中查找设备项。

device_get_env()返回AJAX调用,可能是成功/ 200或错误/ 404。

因此,除非所有承诺都得到解决,否则我的Promises.all将不会返回。

我一直在挖掘如何克服这一点。

尝试实施此解决方案:https://stackoverflow.com/a/30378082/1913289,但我在此处遇到此错误:

TypeError: device_get_env(env).catch is not a function. (In 'device_get_env(env).catch(function(err) {return err} )', 'device_get_env(env).catch' is undefined)

用这里的代码解决这个问题的方法是什么?

@Bergi

建议的

UPD:实施

function get_token_data(env, auth) {
    var client_id = env_tokens[env].client_id;
    var client_secret = env_tokens[env].client_secret;
    var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";

    return Promise.resolve(
        $.ajax({
            url: "https://" + env + ".xxxx.com/oauth/token",
            method: "POST",
            data: {
                "client_id": client_id,
                "client_secret": client_secret,
                "audience": audience,
                "grant_type": "client_credentials"
            },
            dataType: 'json'
        })
    )
}


function device_get_env(env) {
    var env = ...;
    var device_id = ...;

    return get_token_data(env, 0).then(function(data) {
        var url_base = ... ;

        return Promise.resolve(
            $.ajax({
                url: url_base,
                method: "GET",
                dataType: 'json',
                headers: { Authorization: data.token_type + " " + data.access_token }
            })
        )
    });
}


Promise.all(env_array.map(function(env) {
    return device_get_env(env).then(null, function(err) { return err });
})).then(function(data) {
    console.log(data);
}).catch(function(data) {
    console.log(data);
});

UPD1:

Promise.all(env_array.map(function(env) {
    return device_get_env(env).catch(function(err) {return err} );
})).then(function(data) {
    console.log(data);
}).catch(function(data) {
    console.log(data);
});

最终更新: 我使用了fetch:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Supplying_request_options

替换我的AJAX http请求。

  

fetch()返回的Promise不会拒绝HTTP错误状态,即使>如果响应是HTTP 404或500.相反,它将正常解析> (将ok状态设置为false),它只会拒绝网络故障>或者如果有任何事情妨碍了请求的完成。

Promise.all示例:

Promise.all(env_array.map(function(env) {
    return device_get_env(env);
})).then(function(data) {
    console.log(data);
}).catch(function(data) {
    console.log(data);
});

获取示例:

function get_token_data(env, auth) {
    var client_id = env_tokens[tenant].client_id;
    var client_secret = env_tokens[env].client_secret;
    var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";

    var url_base = "https://" + env + ".xxxx.com/oauth/token";
    var myInit = {
        method: 'POST',
        mode: 'cors',
        dataType: 'json',
        cache: 'default',
        data: {
            "client_id": client_id,
            "client_secret": client_secret,
            "audience": audience,
            "grant_type": "client_credentials"
        }
    };

    return fetch(url_base, myInit);
}

2 个答案:

答案 0 :(得分:3)

您的问题是device_get_env(env)返回jQuery承诺,而不是ES6承诺。那些don't have a .catch() method until v3.0 ......

要解决此问题,您可以

  • 更新jQuery,
  • return Promise.resolve($.ajax(…))或中执行get_token_data
  • dodge the jQuery promise
  • 使用.then(null, function(err) { return err })代替.catch(…)

答案 1 :(得分:2)

您的第一个线索是您没有在代码中的某处返回Promise,这是您的错误:

TypeError: device_get_env(env).catch is not a function.

错误告诉您正在尝试在没有.catch()方法的对象上调用catch()(即使AJAX对象在技术上“可以”,早期版本的jQuery没有catch()方法。所以一个解决方案就是升级你的jQuery 1 版本。

您的特殊问题是您没有从get_token_data()函数中获得您期望的AJA Promise,而是返回jQuery Promise。

因此,如果您通过catch()中的Promise.resolve()将jQuery承诺包装/投射到get_token_data()能够的ES6承诺,那么您应该走在正确的轨道上:

function get_token_data(env, auth) {
  var client_id = env_tokens[env].client_id;
  var client_secret = env_tokens[env].client_secret;
  var audience = auth == 1 ? "https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";

  var ajaxOptions = {
    url: "https://" + env + ".xxxx.com/oauth/token",
    method: "POST",
    dataType: 'json',
    data: {
      "client_id": client_id,
      "client_secret": client_secret,
      "audience": audience,
      "grant_type": "client_credentials"
    }
  };

  // here is where the magic happens to cast your 
  // jQuery Promise into a 'catchable' Promise 
  return Promise.resolve($.ajax(ajaxOptions));
};

我无法测试此代码,因此您可能需要对其进行调整,但这是基本的想法。

希望这有帮助!

1 感谢@Bergi reminding me of this