- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在运行外部代码,作为对node.js服务的第三方扩展。 API方法返回 promise 。已解决的 promise 意味着成功执行了操作,失败的 promise 意味着执行操作存在一些问题。
现在这是我遇到麻烦的地方。
由于第3方代码未知,因此可能存在错误,语法错误,类型问题以及可能导致node.js引发异常的多种情况。
但是,由于所有代码都包装在Promise中,因此这些抛出的异常实际上会以失败的Promise的形式返回。
我试图将函数调用放在try/catch块中,但从未触发过:
// worker process
var mod = require('./3rdparty/module.js');
try {
mod.run().then(function (data) {
sendToClient(true, data);
}, function (err) {
sendToClient(false, err);
});
} catch (e) {
// unrecoverable error inside of module
// ... send signal to restart this worker process ...
});
最佳答案
崩溃并重新启动进程不是处理错误甚至错误的有效策略。在Erlang上没问题,那里的过程很便宜,并且做一件孤立的事情,例如为单个客户服务。这不适用于节点,在节点上,流程的成本增加了几个数量级,并一次为成千上万的客户提供服务
假设您的服务每秒处理200个请求。如果其中的1%到达了代码中的抛出路径,则每秒将导致20个进程关闭,大约每50毫秒关闭一次。如果您有4个核心,每个核心1个进程,则将在200ms内丢失它们。因此,如果一个进程启动并准备服务请求所需的时间超过200毫秒(对于不加载任何模块的节点进程,最低成本约为50毫秒),那么我们现在已经成功地实现了全面的拒绝服务。更不用说用户遇到错误了,往往会做类似重复刷新页面,从而使问题更加复杂。
域无法解决问题,因为它们是cannot ensure that resources are not leaked。
在#5114和#5149问题上了解更多信息。
现在,您可以尝试对此“变得聪明”,并基于一定数量的错误制定某种流程回收策略,但是无论采用哪种策略,都会严重改变节点的可伸缩性配置文件。我们每个进程每秒要处理几十个请求,而不是数千个。
但是,promise会捕获所有异常,然后以与同步异常在堆栈中向上传播非常相似的方式传播它们。另外,他们经常提供finally
方法,相当于try...finally
。由于这两个功能,我们可以通过构建“上下文管理器”来封装该清理逻辑(类似于python中的with
,C#中的using
或try-with-resources
在Java)中总是会清理资源。
假设我们的资源用acquire
和dispose
方法表示为对象,这两种方法均返回promise。调用函数时未建立任何连接,我们仅返回资源对象。稍后将由using
处理此对象:
function connect(url) {
return {acquire: cb => pg.connect(url), dispose: conn => conn.dispose()}
}
我们希望API像这样工作:
using(connect(process.env.DATABASE_URL), async (conn) => {
await conn.query(...);
do other things
return some result;
});
我们可以轻松实现以下API:
function using(resource, fn) {
return Promise.resolve()
.then(() => resource.acquire())
.then(item =>
Promise.resolve(item).then(fn).finally(() =>
// bail if disposing fails, for any reason (sync or async)
Promise.resolve()
.then(() => resource.dispose(item))
.catch(terminate)
)
);
}
使用
fn
参数返回的promise链完成后,将始终处理资源。即使在该函数(例如从
JSON.parse
)或其内部
.then
闭包(如第二个
JSON.parse
)中引发了错误,或者链中的promise被拒绝(等同于调用了错误的回调)。这就是为什么它对于 promise 捕获错误并传播错误如此重要的原因。
process.nextTick(() => { throw e });
。哪种实现才有意义可能取决于您的设置-基于nextTick的实现的工作方式类似于回调如何保释。
function unwrapped(arg1, arg2, done) {
var resource = allocateResource();
mayThrowError1();
resource.doesntThrow(arg1, (err, res) => {
mayThrowError2(arg2);
done(err, res);
});
}
mayThrowError2()
在内部回调中,即使抛出,即使在另一个promise的
unwrapped
中调用了
.then
,它也会使进程崩溃。这类错误通常不会被典型的
promisify
包装程序捕获,并且将继续照常导致进程崩溃。
mayThrowError1()
中调用
.then
,将被promise捕获,并且内部分配的资源可能会泄漏。
promisify
版本,以确保所有引发的错误均不可恢复,并导致进程崩溃:
function paranoidPromisify(fn) {
return function(...args) {
return new Promise((resolve, reject) =>
try {
fn(...args, (err, res) => err != null ? reject(err) : resolve(res));
} catch (e) {
process.nextTick(() => { throw e; });
}
}
}
}
如果在未包装的抛出情况下在另一个promise的
.then
回调中使用promisified函数,则会导致进程崩溃,并返回到throw-crash范式。
function unwrapped(arg1, arg2, done) {
var resource = allocateResource();
resource.doSomething(arg1, function(err, res) {
if (err) return done(err);
resource.doSomethingElse(res, function(err, res) {
resource.dispose();
done(err, res);
});
});
}
为什么?因为当
doSomething
的回调收到错误时,代码会忘记处理资源。
using
为您做到了!
关于javascript - 异常处理,抛出的错误, promise 内,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19528705/
如何从 promise 中退出 promise ? perl6 文档没有提供简单的方法。例如: my $x = start { loop { # loop forever until "qui
我的用户 Controller 中有一个索引操作,其中我试图连续做两件事,并且在它们都有机会完成之前不执行所需的 res.json() 方法。 我有一个加入用户的友谊加入模型。一列是 friender
请帮我解释一下为什么日志结果有两种不同: 方式 1:每 1 秒顺序记录一次 方式 2:1 秒后记录所有元素。 // Way 1 let sequence = Promise.resolve(); [1
我的问题很简单。 Promise.all() 方法可以返回 Promise 吗?让我解释一下: function simpleFunction() { let queue = [];
我正在使用 Promise 从存储中读取文件并转换为 base64 字符串。我有图像数组,使用 RNFS 读取图像 const promise_Images = _Images.map(async (
如果使用非空数组调用 Promise.all 或 Promise.race,它们将返回一个待处理的 Promise: console.log(Promise.all([1])); // prints
Promise.all 是否可以在没有包装 promise 的情况下返回链的最后一个值? 如果不使用 await,它在我的上下文中不起作用 没有包装的例子: function sum1(x){ r
我一直在玩 promise,通常能想出如何处理好它们,但在这种情况下,我不知道如何删除一个 promise-wrapping level。 代码如下: let promise2 = promise1.
考虑以下嵌套的Promises结构: const getData = async() => { const refs = [{ name: "John33", age: 3
我已经阅读了 Promise/A+ 规范,但据我了解,还有诸如 Promise/A 和 Promise 之类的东西。它们之间有什么区别? Promise 和 Promise/A 规范也是如此吗?如果是
当我运行以下代码时: my $timer = Promise.in(2); my $after = $timer.then({ say "2 seconds are over!"; 'result'
以下简单的 promise 是发誓的,我不允许打破它。 my $my_promise = start { loop {} # or sleep x; 'promise re
我正在尝试扩展Promise: class PersistedPromise extends Promise { } 然后在派生类上调用静态resolve以直接创建一个已解决的Promise: Per
我有两个返回 promise 的函数,我独立使用它们作为: getLocal().then(...) 和 getWeb().then(...) 但是现在我遇到了一个奇怪的问题: 1) 我需要第三个
我不知道 promise.all 解决方案中的 promise.all 是否是一个好的实践。我不确定。 我需要从一组用户获取信息,然后通过此信息响应,我需要发送消息通知。 let userList =
我一直在尝试使用 queueMicrotask() 函数,但我没有弄清楚当回调是微任务时回调的优先级如何。查看以下代码: function tasksAndMicroTasks() { const
我一直在尝试使用 queueMicrotask() 函数,但我没有弄清楚当回调是微任务时回调的优先级如何。查看以下代码: function tasksAndMicroTasks() { const
今年早些时候,我在 Pharo Smalltalk 参与了一个 promise 项目。这个想法是为了实现以下行为: ([ 30 seconds wait. 4 ]promiseValue )then:
大家好,提前感谢您的帮助。 下面是我正在尝试做的事情 function1(){ throw some error(); } function2() { // dosomething suc
我有以下未解析的代码。f2 解决了,所以我不会添加该代码,它是 f1 我有问题。 我调用函数,它到达最里面如果,它调用函数“find”,它执行函数 findId,完美返回 Id,然后执行 editId
我是一名优秀的程序员,十分优秀!