为什么承诺 returns 也解决拒绝

Why Promise returns also Resolve on Reject

有人可以解释一下,为什么 Promise 在调用 reject 时会触发 then() 函数(以及 catch() 函数)?

调用 resolve 时,只有 then() 被触发 - OK

当调用 reject 时,then() 和 catch() 函数都会被调用 - 问题

static logIn(email, password) {

    async function getSession () {

        let data = new FormData();
        data.append('email', email);
        data.append('password', password);

        const response = await fetch(
            url,
            {
                method: 'POST',
                mode:   'cors',
                body:   data,
                cache:  'no-cache',
                headers: {
                    'Accept': 'application/json',
                },
            }
        );

        const json = await response.json();

        return json;
    }

    return new Promise((resolve, reject) => {
        getSession()
            .then(json => {
                if (json.status === 'ok') {
                    resolve('OK');
                } else {
                    reject('LogIn failed.');
                }
            })
            .catch(error => reject('LogIn failed.'))

    });

};

logIn()
    .then(console.log('logged in'))
    .catch(error => console.log('not logged in'));

调用 onFulfilled 或 onRejected 并带有承诺的实现值或拒绝原因(视情况而定),并且 return 一个新的承诺解析为被调用处理程序的 return 值。

注意这一行:

.then(console.log('logged in'))

then 方法需要 callback,但您正在调用函数并将 return 值作为参数传递。如果 console.log return 编辑了一个函数,该函数将由 then 在内部调用,以防 promise 得到解决。但事实并非如此,因为 console.log 没有 return 值! (它只是打印并退出)。

在 javascript 中,没有 return 值等于 undefined。因此,您所做的是 在任何情况下都调用 console.log 并将未定义作为参数传递。因此,您的代码相当于:

console.log('logged in');
...
  .then(undefined)
  ...

可能,您的意思是将日志记录回调作为参数传递,并让 Promise 在解析时调用该回调:

.then(() => console.log('logged in'));

或者,为了更清楚地了解正在发生的事情,您可以这样看:

function log() {
  console.log('logged in');
}

...
  .then(log);

我们不是调用函数,只是传递引用!

Promise 捕获后继续,尽管您试图将 promise 包装在 promise 中,因此您可以手动更改行为,这是一种反模式。链接承诺本身会更好,这样你就可以处理承诺链中的错误,然后继续执行(所以中间的捕获仍然可以跟随一个 then)。

不需要 .catch(error => reject('LogIn failed.')) ,因为如果您只是 return 来自 getSession() 的承诺,底部的 catch 语句将捕获错误。您正在尝试创建自己的 Promise,但是由于已经有一个 return 从 getSession() 编辑的 Promise,所以您真正想要做的是 return 直接从 return 中获得 Promise。

最后,您在底部写了一个 console.log 而没有将其包装在回调函数中,因此它会在调用 promise 时同步触发,而不是在 .then 触发时触发。

更简洁的解决方案是:

.....

    // return the promise from getSession, why wrap it in another?
    return getSession()
        .then(json => {
            if (json.status === 'ok') {
                return 'OK';
            } else {
                // Throwing an error in a then callback will trigger the catch block below
                throw new Error('LogIn failed.');
            }
        });
}

logIn()
    .then(() => console.log('logged in'))
    .catch(error => console.log('not logged in'));