【问题标题】:Porting Promise Chaining from AngularJs to VueJs将 Promise Chaining 从 AngularJs 移植到 VueJs
【发布时间】:2023-11-11 16:43:01
【问题描述】:

与我的上一个问题相似,但不同之处足以让我不知所措。我在 AngularJs 中有以下函数,需要在 VueJs 中重新创建。我有两种类似的方式我尝试在 VueJs 中编写这个,但是它们都导致了很多站点异常。

AngularJs

var foo = function(obj, config) {
    if (config.skip) {
        return $q.reject("Skipping");
    }
    var deferred = $q.defer();
    obj.promise = deferred.promise;
    if (obj.hasValue()) {
        deferred.resolve(obj);
    } else {
        "/api/callToApi".$promise.then(function(res) {
            if (res) {
                deferred.resolve(res);
            else {
                deferred.reject(res);
            }
         });
    }
    return deferred.promise;
}

VueJs - 取 1。我很确定这个缺少实际的 Promise 链接,不知道如何正确设置它。

var foo = function(obj, config) {
    let returnEarly = false;
    let promise = new Promise((resolve, reject) => {
        returnEarly = true;
        reject("Skipping"):
    }
    if (returnEarly) {
        return promise;
    }
    obj.promise = promise;
    return new Promise((resolve, reject) => {
        if (obj.hasValue()) {
            resolve(obj);
        } else {
            axios.get("/api/callToApi").then(function(res) {
                if (res) {
                    resolve(res);
                } else {
                    reject(res);
                }
            }
        }
    }
}

执行 1 时出现控制台错误

Uncaught (in promise) Error: Request failed with status code 404
    at XMLHttpRequest.__capture__.onreadystatechange

VueJs - 采取 2。我认为这种方式会返回正确的链接,但在运行 jest 测试时我收到错误 Timeout - Async callback was not invoked within the 5000ms timeout

var foo = function(obj, config) {
    let returnEarly = false;
    let promise = new Promise((resolve, reject) => {
        returnEarly = true;
        reject("Skipping"):
    }
    if (returnEarly) {
        return promise;
    }
    obj.promise = promise;
    return promise.then(() => {
        return new Promise((resolve, reject) => {
            if (obj.hasValue()) {
                resolve(obj);
            } else {
                axios.get("/api/callToApi").then(function(res) {
                    if (res) {
                        resolve(res);
                    } else {
                        reject(res);
                    } 
                }
            }
        }
    }
}

【问题讨论】:

    标签: javascript angularjs vue.js promise es6-promise


    【解决方案1】:

    这是纯 JavaScript,并非特定于 Vue。

    通常不需要将 promise 分配给 obj.promise,因为它是从函数返回的。

    过度使用new Promise 被称为promise 构造函数反模式。如果已经有一个 promise(Axios 返回一个),则不需要创建一个新的,这会导致冗余且容易出错的代码(这可能是 Async callback was not invoked... 错误的原因)。如果需要创建新的 Promise,可以使用快捷方式 Promise 方法。

    应该是这样的:

    function(obj, config) {
        if (config.skip) {
            return Promise.reject("Skipping");
        }
    
        if (obj.hasValue()) {
            return Promise.resolve(obj);
        } else {
            return axios("/api/callToApi").then(function(res) {
                if (res)
                    return res;
                else 
                    throw res;
                }
             });
        }
    }
    

    一般来说,除了Error 对象之外的任何错误都是一种不好的做法。

    还要注意,Axios 响应对象总是真实的,可能需要是res.data

    写成async..await会更简洁。

    【讨论】:

    • 再次感谢 Estus 的帮助!我学到了很多关于 Promise 反模式的知识。再次感谢