【Javascript】 Promise 对象(二)
【Javascript】 Promise 对象(一)-CSDN博客
Promise.all()
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有
p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(2)只要
p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
下面是一个具体的例子。
// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {return getJSON('/post/' + id + ".json");
});Promise.all(promises).then(function (posts) {// ...
}).catch(function(reason){// ...
});
上面代码中,promises是包含 6 个 Promise 实例的数组,只有这 6 个实例的状态都变成fulfilled,或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。
下面是另一个例子。
const databasePromise = connectDatabase();const booksPromise = databasePromise.then(findAllBooks);const userPromise = databasePromise.then(getCurrentUser);Promise.all([booksPromise,userPromise
])
.then(([books, user]) => pickTopRecommendations(books, user));
上面代码中,booksPromise和userPromise是两个异步操作,只有等到它们的结果都返回了,才会触发pickTopRecommendations这个回调函数。
注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
const p1 = new Promise((resolve, reject) => {resolve('hello');
})
.then(result => result)
.catch(e => e);const p2 = new Promise((resolve, reject) => {throw new Error('报错了');
})
.then(result => result)
.catch(e => e);Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
上面代码中,p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。
如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。
const p1 = new Promise((resolve, reject) => {resolve('hello');
})
.then(result => result);const p2 = new Promise((resolve, reject) => {throw new Error('报错了');
})
.then(result => result);Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了
Promise.race()
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve。
const p = Promise.race([fetch('/resource-that-may-take-a-while'),new Promise(function (resolve, reject) {setTimeout(() => reject(new Error('request timeout')), 5000)})
]);p
.then(console.log)
.catch(console.error);
上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。
Promise.allSettled()
有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。但是,现有的 Promise 方法很难实现这个要求。
Promise.all()方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。
const urls = [url_1, url_2, url_3];
const requests = urls.map(x => fetch(x));try {await Promise.all(requests);console.log('所有请求都成功。');
} catch {console.log('至少一个请求失败,其他请求可能还没结束。');
}
上面示例中,Promise.all()可以确定所有请求都成功了,但是只要有一个请求失败,它就会报错,而不管另外的请求是否结束。
为了解决这个问题,ES2020 引入了Promise.allSettled()方法,用来确定一组异步操作是否都结束了(不管成功或失败)。所以,它的名字叫做”Settled“,包含了”fulfilled“和”rejected“两种情况。
Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。
const promises = [fetch('/api-1'),fetch('/api-2'),fetch('/api-3'),
];await Promise.allSettled(promises);
removeLoadingIndicator();
上面示例中,数组promises包含了三个请求,只有等到这三个请求都结束了(不管请求成功还是失败),removeLoadingIndicator()才会执行。
该方法返回的新的 Promise 实例,一旦发生状态变更,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,它的回调函数会接收到一个数组作为参数,该数组的每个成员对应前面数组的每个 Promise 对象。
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);const allSettledPromise = Promise.allSettled([resolved, rejected]);allSettledPromise.then(function (results) {console.log(results);
});
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
上面代码中,Promise.allSettled()的返回值allSettledPromise,状态只可能变成fulfilled。它的回调函数接收到的参数是数组results。该数组的每个成员都是一个对象,对应传入Promise.allSettled()的数组里面的两个 Promise 对象。
results的每个成员是一个对象,对象的格式是固定的,对应异步操作的结果。
// 异步操作成功时
{status: 'fulfilled', value: value}// 异步操作失败时
{status: 'rejected', reason: reason}
成员对象的status属性的值只可能是字符串fulfilled或字符串rejected,用来区分异步操作是成功还是失败。如果是成功(fulfilled),对象会有value属性,如果是失败(rejected),会有reason属性,对应两种状态时前面异步操作的返回值。
下面是返回值的用法例子。
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises);// 过滤出成功的请求
const successfulPromises = results.filter(p => p.status === 'fulfilled');// 过滤出失败的请求,并输出原因
const errors = results.filter(p => p.status === 'rejected').map(p => p.reason);
Promise.any()
ES2021 引入了Promise.any()方法。该方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
Promise.any([fetch('https://v8.dev/').then(() => 'home'),fetch('https://v8.dev/blog').then(() => 'blog'),fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => { // 只要有一个 fetch() 请求成功console.log(first);
}).catch((error) => { // 所有三个 fetch() 全部请求失败console.log(error);
});
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。
下面是Promise()与await命令结合使用的例子。
const promises = [fetch('/endpoint-a').then(() => 'a'),fetch('/endpoint-b').then(() => 'b'),fetch('/endpoint-c').then(() => 'c'),
];try {const first = await Promise.any(promises);console.log(first);
} catch (error) {console.log(error);
}
上面代码中,Promise.any()方法的参数数组包含三个 Promise 操作。其中只要有一个变成fulfilled,Promise.any()返回的 Promise 对象就变成fulfilled。如果所有三个操作都变成rejected,那么await命令就会抛出错误。
Promise.any()抛出的错误是一个 AggregateError 实例,这个 AggregateError 实例对象的errors属性是一个数组,包含了所有成员的错误。
下面是一个例子。
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);Promise.any([resolved, rejected, alsoRejected]).then(function (result) {console.log(result); // 42
});Promise.any([rejected, alsoRejected]).catch(function (results) {console.log(results instanceof AggregateError); // trueconsole.log(results.errors); // [-1, Infinity]
});
Promise.resolve()
有时需要将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用。
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
上面代码将 jQuery 生成的deferred对象,转为一个新的 Promise 对象。
Promise.resolve()等价于下面的写法。
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
Promise.resolve()方法的参数分成四种情况。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,比如下面这个对象。
let thenable = {then: function(resolve, reject) {resolve(42);}
};
Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。
let thenable = {then: function(resolve, reject) {resolve(42);}
};let p1 = Promise.resolve(thenable);
p1.then(function (value) {console.log(value); // 42
});
上面代码中,thenable对象的then()方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then()方法指定的回调函数,输出42。
(3)参数不是具有then()方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then()方法的对象,则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');p.then(function (s) {console.log(s)
});
// Hello
上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve()方法的参数,会同时传给回调函数。
(4)不带有任何参数
Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve()方法。
const p = Promise.resolve();p.then(function () {// ...
});
上面代码的变量p就是一个 Promise 对象。
需要注意的是,立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
setTimeout(function () {console.log('three');
}, 0);Promise.resolve().then(function () {console.log('two');
});console.log('one');// one
// two
// three
上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。
Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))p.then(null, function (s) {console.log(s)
});
// 出错了
上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。
Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
Promise.reject('出错了')
.catch(e => {console.log(e === '出错了')
})
// true
上面代码中,Promise.reject()方法的参数是一个字符串,后面catch()方法的参数e就是这个字符串。
Promise.try()
实际开发中,经常遇到一种情况:不知道或者不想区分,函数f是同步函数还是异步操作,但是想用 Promise 来处理它。因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理f抛出的错误。一般就会采用下面的写法。
Promise.resolve().then(f)
上面的写法有一个缺点,就是如果f是同步函数,那么它会在本轮事件循环的末尾执行。
const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');
// next
// now
上面代码中,函数f是同步的,但是用 Promise 包装了以后,就变成异步执行了。
那么有没有一种方法,让同步函数同步执行,异步函数异步执行,并且让它们具有统一的 API 呢?回答是可以的,并且还有两种写法。第一种写法是用async函数来写。
const f = () => console.log('now');
(async () => f())();
console.log('next');
// now
// next
上面代码中,第二行是一个立即执行的匿名函数,会立即执行里面的async函数,因此如果f是同步的,就会得到同步的结果;如果f是异步的,就可以用then指定下一步,就像下面的写法。
(async () => f())()
.then(...)
需要注意的是,async () => f()会吃掉f()抛出的错误。所以,如果想捕获错误,要使用promise.catch方法。
(async () => f())()
.then(...)
.catch(...)
第二种写法是使用new Promise()。
const f = () => console.log('now');
(() => new Promise(resolve => resolve(f()))
)();
console.log('next');
// now
// next
上面代码也是使用立即执行的匿名函数,执行new Promise()。这种情况下,同步函数也是同步执行的。
鉴于这是一个很常见的需求,所以现在有一个提案,提供Promise.try方法替代上面的写法。
const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next
事实上,Promise.try存在已久,Promise 库Bluebird、Q和when,早就提供了这个方法。
由于Promise.try为所有操作提供了统一的处理机制,所以如果想用then方法管理流程,最好都用Promise.try包装一下。这样有许多好处,其中一点就是可以更好地管理异常。
function getUsername(userId) {return database.users.get({id: userId}).then(function(user) {return user.name;});
}
上面代码中,database.users.get()返回一个 Promise 对象,如果抛出异步错误,可以用catch方法捕获,就像下面这样写。
database.users.get({id: userId})
.then(...)
.catch(...)
但是database.users.get()可能还会抛出同步错误(比如数据库连接错误,具体要看实现方法),这时你就不得不用try...catch去捕获。
try {database.users.get({id: userId}).then(...).catch(...)
} catch (e) {// ...
}
上面这样的写法就很笨拙了,这时就可以统一用promise.catch()捕获所有同步和异步的错误。
Promise.try(() => database.users.get({id: userId})).then(...).catch(...)
事实上,Promise.try就是模拟try代码块,就像promise.catch模拟的是catch代码块。
相关文章:
【Javascript】 Promise 对象(二)
【Javascript】 Promise 对象(一)-CSDN博客 Promise.all() Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。 const p Promise.all([p1, p2, p3]);上面代码中,Promise.all()方法接受一个数组作为参数&…...
细说C++反向迭代器:原理与用法
文章目录 一、引言二、反向迭代器的原理与实现细节三、模拟实现C反向迭代器反向迭代器模板类的设计反向迭代器的使用示例与测试 一、引言 迭代器与反向迭代器的概念引入 迭代器(Iterator)是C标准模板库(STL)中的一个核心概念&am…...
SpringBoot(依赖管理和自动配置)
文章目录 1.基本介绍1.springboot是什么?2.快速入门1.需求分析2.环境配置1.确认开发环境2.创建一个maven项目3.依赖配置 pom.xml4.文件目录5.MainApp.java (启动类,常规配置)6.HelloController.java (测试Controller&a…...
cad怎么转换成黑白的pdf图纸?分享3个常用的软件!
在工程设计、建筑、机械制造等领域,CAD图纸的应用非常广泛。然而,有时出于某些需要,我们可能需要将CAD图纸转换为黑白的PDF格式。那么,如何实现这一转换呢?本文将为您详细介绍几种常用的转换软件及其操作步骤。 迅捷CA…...
maven本地仓库依赖上传到远程仓库
本地仓库上传到远程仓库 批量上传: 批量本地仓库依赖(jar包)上传脚本: #!/bin/bash # copy and run this script to the root of the repository directory containing files # this script attempts to exclude uploading itse…...
ISIS多区域实验简述
为支持大型路由网络,IS-IS在路由域内采用两级分层结构。 IS-IS网络中三种级别的路由设备:将Level-1路由设备部署在区域内,Level-2路由设备部署在区域间,Level-1-2路由设备部署在Level-1和Level-2路由设备的中间。 实验拓扑图&…...
go语言基础笔记
1.基本类型 1.1. 基本类型 bool int: int8, int16, int32(rune), int64 uint: uint8(byte), uint16, uint32, uint64 float32, float64 string 复数:complex64, complex128 复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部…...
kettle 9.4和Pentoho 9.4下载及安装方法简介
kettle 9.4和Pentoho 9.4下载及安装方法简介 下载地址: https://sourceforge.net/projects/pentaho/files/ 下载步骤: #------------- 一、点击选项卡:summary/ 二、点击第一行链接 https://www.hitachivantara.com/en-us/products/pentaho…...
社交革命的引领者:探索Facebook如何改变我们的生活方式
1.数字社交的兴起 随着互联网的普及,社交媒体成为我们日常生活的重要组成部分。Facebook作为其中的先驱,从最初的社交网络演变成了一个拥有数十亿用户的全球化平台。它不仅改变了我们与世界互动的方式,还深刻影响了我们的社交习惯、人际关系以…...
常用的推荐算法
推荐系统在帮助用户发现可能感兴趣的产品、服务或信息方面发挥着重要作用。下面是一些常用的推荐算法: 1. 协同过滤 用户基于协同过滤(User-Based Collaborative Filtering) 基于用户之间的相似性为用户推荐物品。算法会找出与目标用户兴趣…...
使用Python进行图片格式转化/分辨率转化
一.下载python PIY插件库 PIP下载命令: pip install pillow -i https://mirrors.aliyun.com/pypi/simple PIY插件库:pillow Installation - Pillow (PIL Fork) 10.3.0.dev0 documentation 二.分辨率转化 from PIL import Image import osresolution (1024, 1024) with Image…...
植物神经功能紊乱患者每天从5片黛力新减少至2片,只因找对了治疗方法!
植物神经功能紊乱是一种常见的心理疾病,其症状包括焦虑、失眠、疲劳、头痛、胃肠不适等,给患者带来很大的困扰。然而,这种疾病是可以治疗的。本文将介绍一位植物神经功能紊乱患者的治疗经历,希望能够帮助更多的人了解和治疗此病。…...
SpringSecurity 快速入门
文章目录 1. 认证授权概述1.1 认证授权概念1.1.1 认证1.1.2 授权 1.2 权限数据模型1.3 RBAC权限模型1.3.1 介绍1.3.2 基于角色访问控制1.3.3 基于资源访问控制 1.4 常见认证方式1.4.1 Cookie-Session1.4.2 jwt令牌无状态认证 1.5 技术实现 2. SpringSecurity入门2.1 介绍2.2 入…...
MySQL--执行一条 select 语句,期间发生了什么?
执行一条 SQL 查询语句,期间发生了什么? 连接器:建立连接,管理连接、校验用户身份;查询缓存:查询语句如果命中查询缓存则直接返回,否则继续往下执行。MySQL 8.0 已删除该模块;解析 …...
DeepL:word文档导出后不能编辑
参考解决用DeepL翻译文档后不能编辑问题_deepl翻译出来的文档怎么编辑-CSDN博客 1、将deepL导出的word文档另存为.xml文件 2、将.xml文件以txt格式打开,查找内容:<w:documentProtection,删除整个标签(包括<w: ...>&…...
PCL 约束Delaunay三角网(版本二)
目录 一、算法概述二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法概述 PCL 点云Delaunay三角剖分一文给出了PCL中Delaunay三角网算法的基础用法。本文在基础用法的基…...
位运算#蓝桥杯
位运算#蓝桥杯 文章目录 位运算#蓝桥杯1、小蓝学位运算2、异或森林3、位移4、笨笨的机器人5、博弈论 1、小蓝学位运算 #include<bits/stdc.h> using namespace std; using LL long long; const LL N 1e97; template<int kcz> struct ModInt { #define T (*this)…...
Python yield from
yield from是Python生成器(generator)中的一个语法,用于简化生成器的操作。它可以使一个生成器委托部分操作给另一个生成器,从而简化代码。yield from在Python 3.3及更高版本中被引入。 在使用yield from之前,我们需要…...
Atcoder TUPC 2023(東北大学プログラミングコンテスト 2023)E. And DNA(矩阵快速幂+拆位讨论)
题目 长为n(3<n<1e9)的数组,第i个数ai在[0,m](m<1e9)之间 对于i∈[1,n],均满足a[i](a[i-1]&a[i1])m,求这样可能的数组的方案数 特别地,认为a[0]a[n],a[n1]a[1],即这个数组是个环形的数组 思路来源 官…...
Matlab/simulin光伏发电直流串联故障电弧模型仿真
参考文献 模型复现...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
【java】【服务器】线程上下文丢失 是指什么
目录 ■前言 ■正文开始 线程上下文的核心组成部分 为什么会出现上下文丢失? 直观示例说明 为什么上下文如此重要? 解决上下文丢失的关键 总结 ■如果我想在servlet中使用线程,代码应该如何实现 推荐方案:使用 ManagedE…...
