带有拒绝调用的Promise构造函数与抛出错误

IT技术 javascript promise
2021-02-02 08:30:05

在以下代码中:

var p1 = new Promise(function (resolve, reject) {
    throw 'test1';
});

var p2 = new Promise(function (resolve, reject) {
    reject('test2');
});

p1.catch(function (err) {
    console.log(err); // test1
});

p2.catch(function (err) {
    console.log(err); // test2
});

api使用reject(in p2)Promise和使用 抛出错误 (in p1)之间有什么区别throw吗?

它完全一样吗?

如果相同,那为什么我们需要reject回调呢?

4个回答

api使用reject(in p2)Promise和使用 抛出错误 (in p1)之间有什么区别throw吗?

是的,您不能throw异步使用reject而是回调。例如,一些超时:

new Promise(_, reject) {
    setTimeout(reject, 1000);
});

它完全一样吗?

不,至少当其他代码遵循您的语句时不会。throw立即完成解析器功能,同时调用reject继续正常执行 - 在将Promise“标记”为拒绝后。

此外,如果您throw错误对象,引擎可能会提供不同的异常调试信息

对于您的具体示例,您是对的,p1并且p2与外部无法区分。

@BenjaminGruenbaum 嗯,我以为我遇到了一个引擎,它在创建和抛出错误之间的堆栈跟踪中有所区别。不记得哪个:-/
2021-03-15 08:30:05
如果您发现一个错误,请务必提交错误报告 - 错误在创建时创建堆栈跟踪,而不是在抛出时创建:)
2021-03-18 08:30:05
在像 Angular2 这样的框架中,使用 throw 也会触发 Angular ErrorHandler 而使用 reject 可以避免这种情况。
2021-04-02 08:30:05
“如果您抛出错误对象,引擎可能会提供不同的异常调试信息。” - 我不认为这部分对于 throw 和拒绝来说是正确的,还是你的意思是一般的?
2021-04-09 08:30:05

不,没有,两者完全相同。唯一的区别以及我们需要的原因reject是当您需要异步拒绝时 - 例如,如果您正在转换基于回调的 API,它可能需要发出异步错误信号。

var p = new Promise(function(resolve, reject){
    someCallbackApi(function(err, data){
        if(err) reject(err); // CAN'T THROW HERE, non promise context, async.
        else resolve(data);
    });
});
可能是因为你说“完全相同”然后继续解释差异......?
2021-03-14 08:30:05
@PeterWhitfield 据我所知,这仍然没问题——它们在 OP 的用例中完全相同,但是在另一种使用模式中给定其他输入,它们是不同的。
2021-04-07 08:30:05

我知道这有点晚了,但我真的不认为这些答案中的任何一个都不能完全回答我发现这个问题时的问题,这是一个更完整的例子。

var p1 = new Promise(function (resolve, reject) {
    throw 'test 1.1'; //This actually happens
    console.log('test 1.1.1'); //This never happens
    reject('test 1.2'); //This never happens because throwing an error already rejected the promise
    console.log('test 1.3'); //This never happens
});

var p2 = new Promise(function (resolve, reject) {
    reject('test 2.1'); //This actually happens
    console.log('test 2.1.1'); //This happens BEFORE the Promise is rejected because reject() is a callback
    throw 'test 2.2'; //This error is caught and ignored by the Promise
    console.log('test 2.3'); //This never happens
});

var p3 = new Promise(function (resolve, reject) {
    setTimeout(function() { reject('test 3.1');}, 1000); //This never happens because throwing an error already rejected the promise
    throw('test 3.2'); //This actually happens
    console.log('test 3.3'); //This never happens
});

var p4 = new Promise(function (resolve, reject) {
    throw('test 4.1'); //This actually happens
    setTimeout(function() { reject('test 4.2');}, 1000); //This never happens because throwing an error already rejected the promise
    console.log('test 4.3'); //This never happens
});

var p5 = new Promise(function (resolve, reject) {
    setTimeout(function() { throw('test 5.1');}, 1000); //This throws an Uncaught Error Exception
    reject('test 5.2'); //This actually happens
    console.log('test 5.3'); //This happens BEFORE the Promise is rejected because reject() is a callback
});

var p6 = new Promise(function (resolve, reject) {
    reject('test 6.1'); //This actually happens
    setTimeout(function() { throw('test 6.2');}, 1000); //This throws an Uncaught Error Exception
    console.log('test 6.3'); //This happens BEFORE the Promise is rejected because reject() is a callback
});


p1.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test1
});

p2.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test2
});

p3.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test3
});

p4.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test4
});

p5.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test5
});

p6.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test6
});

一个非常有趣的观察是,如果您使用throw它,它将首先由reject处理程序处理,然后在error没有拒绝处理程序的情况下由处理程序处理。

使用拒绝处理程序块

var allowed = false;
var p1 = new Promise(
function(resolve, reject) {
  if (allowed)
    resolve('Success');
  else
//         reject('Not allowed');
    throw new Error('I threw an error')
})

p1.then(function(fulfilled) {
console.log('Inside resolve handler, resolved value: ' + fulfilled);
}, function(rejected) {
console.log('Inside reject handler, rejected value: ' + rejected);
}).catch(function(error) {
console.log('Inside error handler, error value: ' + error);
})

没有拒绝处理程序块

var allowed = false;
var p1 = new Promise(
function(resolve, reject) {
  if (allowed)
    resolve('Success');
  else
//         reject('Not allowed');
    throw new Error('I threw an error')
})

p1.then(function(fulfilled) {
console.log('Inside resolve handler, resolved value: ' + fulfilled);
}).catch(function(error) {
console.log('Inside error handler, error value: ' + error);
})

此外,catch 块将能够捕获resolve处理程序中抛出的任何错误

var allowed = true;
var p1 = new Promise(
function(resolve, reject) {
  if (allowed)
    resolve('Success');
  else
//         reject('Not allowed');
    throw new Error('I threw an error')
})

p1.then(function(fulfilled) {
console.log('Inside resolve handler, resolved value: ' + fulfilled);
throw new Error('Error created inside resolve handler block');
}).catch(function(error) {
console.log('Inside error handler, error value: ' + error);
})

看起来最好使用throw,除非您不能运行某些异步任务,否则您必须将reject回调传递给异步函数。但是有一个变通方法,那就是Promise你的异步功能。更多关于https://stackoverflow.com/a/33446005