Promise.all():在所有 Promises 被解决和/或拒绝后返回结果 [英] Promise.all(): Return a result after all Promises are resolved and/or rejected

查看:152
本文介绍了Promise.all():在所有 Promises 被解决和/或拒绝后返回结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用此代码时遇到问题:

//var env_array = ["env1", "env2", "env3", "env4"];Promise.all(env_array.map(function(env) {返回 device_get_env(env).catch(function(err) { return err });})).then(函数(数据){控制台日志(数据);数据.forEach(功能(条目){console.log(entry.data.connected);});}).catch(函数(数据){控制台日志(数据);});函数 device_get_env(env) {var env = ...;var device_id = ...;返回 get_token_data(env, 0).then(function(data) {var url_base = ... ;返回 $.ajax({网址:url_base,方法:获取",数据类型:'json',标头:{授权:data.token_type + " " + data.access_token}});});}函数 get_token_data(env, auth) {var client_id = env_tokens[env].client_id;var client_secret = env_tokens[env].client_secret;var 观众 = auth == 1 ?"https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";返回 $.ajax({url: "https://" + env + ".xxxx.com/oauth/token",方法:POST",数据: {client_id":client_id,client_secret":client_secret,观众":观众,"grant_type": "client_credentials"},数据类型:'json'});}

基本上我需要遍历 env_array 并在我的一些环境中找到设备项.

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

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

我一直在研究如何克服这个问题.

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

TypeError: device_get_env(env).catch 不是函数.(在'device_get_env(env).catch(function(err) {return err})'中,'device_get_env(env).catch'是未定义的)

有什么办法可以用我的代码解决这个问题吗?

UPD:@Bergi 建议的实现

function get_token_data(env, auth) {var client_id = env_tokens[env].client_id;var client_secret = env_tokens[env].client_secret;var 观众 = auth == 1 ?"https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";返回 Promise.resolve($.ajax({url: "https://" + env + ".xxxx.com/oauth/token",方法:POST",数据: {client_id":client_id,client_secret":client_secret,观众":观众,"grant_type": "client_credentials"},数据类型:'json'}))}函数 device_get_env(env) {var env = ...;var device_id = ...;返回 get_token_data(env, 0).then(function(data) {var url_base = ... ;返回 Promise.resolve($.ajax({网址:url_base,方法:获取",数据类型:'json',标头:{ 授权:data.token_type + " " + data.access_token }}))});}Promise.all(env_array.map(function(env) {返回 device_get_env(env).then(null, function(err) { return err });})).then(函数(数据){控制台日志(数据);}).catch(函数(数据){控制台日志(数据);});

UPD1:

Promise.all(env_array.map(function(env) {返回 device_get_env(env).catch(function(err) {return err} );})).then(函数(数据){控制台日志(数据);}).catch(函数(数据){控制台日志(数据);});

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

替换我的 AJAX http 请求.

<块引用>

即使响应是 HTTP 404 或 500,从 fetch() 返回的 Promise 也不会拒绝 HTTP 错误状态.相反,它将正常解析 >(将 ok 状态设置为 false),并且只会网络故障时拒绝 > 或者如果有任何原因阻止请求完成.

Promise.all 示例:

Promise.all(env_array.map(function(env) {返回 device_get_env(env);})).then(函数(数据){控制台日志(数据);}).catch(函数(数据){控制台日志(数据);});

获取示例:

function get_token_data(env, auth) {var client_id = env_tokens[租户].client_id;var client_secret = env_tokens[env].client_secret;var 观众 = auth == 1 ?"https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";var url_base = "https://" + env + ".xxxx.com/oauth/token";var myInit = {方法:'POST',模式:'cors',数据类型:'json',缓存:'默认',数据: {client_id":client_id,client_secret":client_secret,观众":观众,"grant_type": "client_credentials"}};返回获取(url_base,myInit);}

解决方案

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

TypeError: device_get_env(env).catch 不是函数.

错误告诉您,您正试图在一个没有 catch() 方法的对象上调用 .catch()(即使AJAX 对象在技术上是thenable"的,早期版本的 jQuery 没有 catch() 方法.所以一种解决方案是升级你的 jQuery1 版本.>

您的特殊问题是您没有从 get_token_data() 函数中的 AJAX 调用中获得您期望的 ES6 承诺,而是返回了一个 jQuery 承诺.

因此,如果您通过 get_token_data() 中的 Promise.resolve() 将 jQuery 承诺包装/转换为 catch()-able ES6 Promise代码> 那么你应该在正确的轨道上:

function get_token_data(env, auth) {var client_id = env_tokens[env].client_id;var client_secret = env_tokens[env].client_secret;var 观众 = auth == 1 ?"https://" + env + ".xxxx.com/api/v2/" : "yyyy.com";var ajaxOptions = {url: "https://" + env + ".xxxx.com/oauth/token",方法:POST",数据类型:'json',数据: {client_id":client_id,client_secret":client_secret,观众":观众,"grant_type": "client_credentials"}};//这里是魔法发生的地方//jQuery Promise 变成可捕获"的 Promise返回 Promise.resolve($.ajax(ajaxOptions));};

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

希望这会有所帮助!

1感谢@Bergi 提醒我这一点.

I am having trouble with this code:

// 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'
    });
}

Basically I need to iterate over env_array and find device items in some of my environments.

device_get_env() returns AJAX call, which could be a success/200 or error/404.

Thus my Promises.all won't return unless all promises are resolved.

I've been digging how to overcome this.

Been trying to implement this solution: https://stackoverflow.com/a/30378082/1913289, but I'm having this error here:

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)

Any way to solve this with my code here?

UPD: implementation suggested by @Bergi

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

FINAL UPD: I used fetch: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Supplying_request_options

to replace my AJAX http requests.

The Promise returned from fetch() won’t reject on HTTP error status even > if the response is an HTTP 404 or 500. Instead, it will resolve normally > (with ok status set to false), and it will only reject on network failure > or if anything prevented the request from completing.

Promise.all example:

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

fetch example:

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

解决方案

Your first clue that you aren't returning a Promise somewhere in your code is in your error:

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

The error is telling you that you are trying to call .catch() on an object that doesn't have a catch() method on it (even though AJAX objects are technically "thenable", earlier versions of jQuery don't have a catch() method. So one solution is to upgrade your version of jQuery1.

Your particular problem is that you are not getting the ES6 Promise you expect from the AJAX call in your get_token_data() function, instead, you are returning a jQuery Promise.

So if you wrap/cast the jQuery promise to a catch()-able ES6 Promise via Promise.resolve() in get_token_data() then you should be on the right track:

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

I can't test this code, so you might need to tweak it, but that is the basic idea.

Hope this helps!

1 Thanks to @Bergi for reminding me of this.

这篇关于Promise.all():在所有 Promises 被解决和/或拒绝后返回结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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