将 Promise Chaining 从 AngularJs 移植到 VueJs

Porting Promise Chaining from AngularJs to VueJs

与我的上一个问题类似,但差异很大,让我不知所措。我在 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。我很确定这个缺少实际的承诺链,不确定如何正确设置它。

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

Take 1 的控制台错误

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

VueJs - 采取 2。我认为这种方式会 return 正确的链接,但是当 运行 开玩笑测试时我得到一个错误 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,不特定于 Vue。

一般不需要给obj.promise分配一个promise,因为它是从函数返回的。

过度使用 new Promise 被称为 promise 构造函数反模式。如果已经有一个 promise(Axios returns 一个),就没有必要创建一个新的,这会导致冗余和容易出错的代码(这可能是 Async callback was not invoked... 错误的原因)。如果需要创建新的承诺,可以使用快捷方式 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 object 之外的任何错误都是不好的做法。

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

写成async..await会更简洁。