基本使用方式:
方法后面跟上 async 表示是一个异步函数。如果调用异步函数
在正常返回的函数中使用 async 修饰的func时,需要用Task{} 进行包装,否则报错
使用方式:
属性也可以 async properties
使用异步属性,必须只能是 get 属性。可写属性不能使用异步属性。
public func resume(returning x: T) 接收 completion 中的数据返回,转换成 async 函数返回。
public func resume(throwing x: E) 进行抛出异常
withCheckedContinuation 方法中的 checked 会在运行时对 *** 作进行检查:是否调用 resume 进行返回。如果不调用会造成资源泄露。多次调用也会造成问题。
continuation 有且只能 resume 一次。
withUnsafeContinuation 的工作机制和 withCheckedContinuation 一致,唯一区别在于运行时不会对 *** 作进行检查。但性能更好。实际使用中 withCheckedContinuation 测试没有问题后,正式发布时使用 withUnsafeContinuation
使用方式如下:
withCheckedContinuation
如果有抛出异常
withCheckedThrowingContinuation
事情的起因是微服务A通过feign调用微服务B的某个接口,报了形如下的异常
负责微服务A的工程师小张就找到负责提供该接口的工程师小李,问小李是不是改动了接口,小李一脸无辜说他最近没对这个接口做任何改动,不过小李还是说道他排查一下。
小李排查的过程如下,他先通过swagger查看他提供给A服务接口是否存在,他一查发现他在swagger上看不到他提供给A服务的接口。于是他怀疑是不是有人动了他的代码,他就去查找最近的git提交记录,发现没人动他的代码,因为项目还没发布,都在测试阶段,他就根据项目集成的git-commit-id-maven-plugin插件定位到测试目前发布具体是哪个版本。(ps:对
git-commit-id-maven-plugin感兴趣的朋友,可以查看之前的文章聊聊如何验证线上的版本是符合预期的版本)。然后他将该版本的代码下到本地进行调试,他发现代码中提供给A的接口还在,target下的class也有提供给A的接口class,但诡异的是swagger就是没显示他提供出去的接口,他一度以为是swagger出了问题,于是他用postman直接请求他提供A的接口,发现报了404。然后他就叫负责同个微服务B的同事小王,也帮忙试一下,发现结果就是404。后面没招,小李就去求助他们项目资深同事小林。
小林的排查思路如下,他先走查一下小李的接口代码,发现他提供的接口实现层的方法上加了一个@Async,示例形如下
小林凭多年的经验直觉告诉小李说,应该是@Async引起。小李很斩钉截铁的说不可能啊,他@Async很早就加了,之前接口都可以访问的,小林一看小李说得那么肯定,他也不好打击小李。于是他接下来做了如下 *** 作,先在项目中yml配置如下参数,开启springweb日志
然后在项目中加了形如下代码,来跟踪接口bean的类型
启动控制台,看日志形如下
发现确实没打印出相关requestMapping映射信息,这可以说明一点就是小李那个接口没有绑定到springmvc映射,也就是出现404的原因。接着观察控制台打印的bean,内容形如下
这很明显这个接口bean已经被jdk动态代理给替换。小李看到控制台打印的信息,若有所思,然后说,我把@Async去掉试下。小李把@Async去掉后,再观察下控制台
通过控制台可以发现,此时接口已经绑定到springmvc映射,而且打印出bean类型是真实对象bean。小李看到这个现象,也百思不得其解,他说道他之前确实是加了@Async,接口也能正常访问。于是小林就问一句,你确定你加了@Async,异步生效了吗,小李说开启spring异步,不都是加@Async吗。小林又问了一句,你在项目中开启异步,除了加@Async,还有做什么处理吗,小李说没了,他之前在项目使用异步就都是加了@Async,也能用了好好的,小林一听,基本上知道为什么小李之前@Async,接口还能正常访问了,小林为了验证想法,就问同负责该项目的小王,说你最近有加什么异步 *** 作吗,小王说有,小林进一步问,你是怎么做的,小王说,他先加@EnabledAsyn,开启异步,然后在业务逻辑层上的方法上加@Async注解。小李一听,说原来使用@Async还要配合@EnabledAsyn啊,他之前都不知道
接着小李说 那在controller是不是就不能使用@Async注解了? ,小林说最好是把加@Async的逻辑挪到service层去处理,不过也不是controller就不能使用@Async注解了,接着小林为了验证这个想法,他把原来实现的接口类去掉,形如下
启动后,查看控制台
此时bean的类型如下
访问接口,打印内容如下
从控制台可以发现,都是>
微信小程序退出账号的前提条件是用户已登陆,且在前端页面和后端服务已记录了用户的登陆状态。退出登陆的 *** 作,相当于清除用户登陆状态的 *** 作。
因此微信小程序实现退出账号的具体流程包括以下几点:
1、用户登陆 *** 作:
(1)微信小程序调用wxlogin获取登录凭证(code)。
(2) 将code传递到后端服务,通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid),并生成与用户一一对应的token值,保存起来,用作用户身份的校验,同时返回给微信小程序客户端。
(3)微信小程序获取到token令牌,保存到本地,即可作为已登陆状态的凭证。
前端代码为:
const login = function () {
wxshowLoading({ title: '登陆中' })
wxlogin()then(res => {
if (reserrMsg === 'login:ok') {
Apilogin(rescode)then(data => {
wxhideLoading()
wxsetStorageSync('token', data) })
}})}
后端服务代码为:
async login(jsCode) {
const { ctx, app } = this;
const APPID = appconfigminiProgramappId;
const SECRET = appconfigminiProgramappSecret;
const url = `>
const res = await ctxcurl(url, { method: 'GET', dataType: 'json' });
const openid = resdataopenid;
const session_key = resdatasession_key;
const str = await appredisget(openid);
if (str && JSONparse(str)accessToken) { // 已登陆
const oldAccessToken = JSONparse(str)accessToken;
await appredisdel(oldAccessToken); // 删除token,实现单点登陆
await appredisdel(openid);}
const accessToken = await ctxhelpercreateWxToken(openid, session_key); // 生成新的token
return accessToken;}
2、退出登陆 *** 作:
(1)点击“退出账号”按钮,调用ajax请求后端退出登陆接口并传递用户token,若退出成功,则清除当前用户登陆状态和token信息。
(2)刷新当前页面数据,清除页面上的用户信息。
(3)后端API接收到客户端传递的用户token,查询数据库判断用户是否已登陆,若登陆,则删除或将token置为无效。
前端代码为:
const logout = function () {
wxshowLoading({ title: '退出登陆中' })
const token = wxgetStorageSync('token')
Apilogout({ token: token })then(data => {
wxhideLoading()
wxremoveStorageSync('token')
refreshPageData()
})}
后端代码为:
async logout(accessToken) {
const { ctx, app } = this;
const userId = await appredisget(accessToken);
if (!userId) ctxthrow(400, '登陆状态已失效');
await appredisdel(userId); // 删除userId
await appredisdel(accessToken); // 删除token
}
扩展资料:
1、微信小程序账号密码登陆和授权登陆后,token保存在loacalStore中,在每次加载接口时,携带上token令牌,向服务端传递已登陆的状态。
2、微信小程序退出登陆需清除登陆状态,当调用微信小程序API中的wxlogin()执行登陆 *** 作,通过登陆接口获取到code后需调用后端接口生成token, 由于安全问题,勿在前端使用密钥生成。在执行退出登陆 *** 作时,需清除localStorage 中缓存的token及用户信息,并刷新当前页面数据。
async function getTitle(){
const title = await drivergetTitle();
consolelog(title)
}
以上是一个minium框架中使用异步获取小程序title的方法,其中,`driver`是minium框架中的驱动对象,`getTitle()`方法用于获取当前页面的title。获取到的title可以通过`consolelog()`方法打印出来。望采纳。
针对小程序的异步
因为懒得去配置async 和await的环境了,wxgetStorageSync是同步的就
直接了在这个基础上了一个重入锁的js来实现同步
/本类主要用来实现同步/
const lockerKey = "wxlocker";
var lockerContainer={};
/
加锁函数
参数:锁名
/
function lock(lockName){
var obj= wxgetStorageSync(lockerKey);
consolelog(111);
consolelog(obj);
if (typeof obj === "undefined" || obj==null||obj==''){
lockerContainerlockName = 1;
wxsetStorageSync(lockerKey, lockerContainer);
}else{
lockerContainer = obj;
if (typeof lockerContainerlockName !== "undefined" && lockerContainerlockName != null && lockerContainerlockName != ''){
lockerContainerlockName = lockerContainerlockName +1;
}else{
lockerContainerlockName = 1;
}
//更新锁
wxsetStorageSync(lockerKey, lockerContainer);
}
}
/
解锁函数
参数:锁名
/
function unlock(lockName){
var obj = wxgetStorageSync(lockerKey);
consolelog(222);
consolelog(obj);
if (typeof obj === "undefined" || obj == null || obj == '') {//没有锁过
return;
} else {
lockerContainer = obj;
if (typeof lockerContainerlockName !== "undefined" && lockerContainerlockName != null && lockerContainerlockName != '') {
if (lockerContainerlockName <=0){
lockerContainerlockName=0;
return;
}else{
lockerContainerlockName = lockerContainerlockName - 1;
}
} else {
return;
}
//更新锁
wxsetStorageSync(lockerKey, lockerContainer);
obj = wxgetStorageSync(lockerKey);
consolelog(obj);
}
}
/
是否被锁函数
参数:锁名
返回值:boolean
/
function isLockedBy(lockName){
var obj = wxgetStorageSync(lockerKey);
if (typeof obj === "undefined" || obj == null || obj == '') {//没有锁过
return false;
} else {
lockerContainer = obj;
if (typeof lockerContainerlockName !== "undefined" && lockerContainerlockName != null && lockerContainerlockName != '') {
if (lockerContainerlockName > 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
}
/
等待函数(等待100millseconds后自动解除)
参数:锁名,间隔毫秒,等待解锁完成后的回调函数
/
function wait(lockName, millseconds,callback){
//100次监控后清空锁
var expireTime = 0;
var timer =setInterval(function () {
consolelog("wait " + millseconds);
if (!isLockedBy(lockName)){
clearInterval(timer);
callback();
}else{//被锁住了
expireTime++;
if (expireTime > 100) {
lockerContainerlockName=null;
//清空锁
wxsetStorageSync(lockerKey, lockerContainer);
clearInterval(timer);
}
}
}, millseconds)
}
moduleexports = {
wait: wait,
unlock: unlock,
lock: lock
}
用法,加锁多少次就要解锁多少次
lock("mylock")
lock("mylock")
unlock("mylock")
unlock("mylock")
wait("mylock",1000,callback)
有很多 async 的面试题,例如
等等,需要找出一个规律
用同步的方式,编写异步。
和 Promise 的关系
async 函数返回结果都是 Promise 对象(如果函数内没返回 Promise ,则自动封装一下)
await 后面跟 Promise 对象:会阻断后续代码,等待状态变为 resolved ,才获取结果并继续执行
await 后续跟非 Promise 对象:会直接返回
总结来看:
异步本质
await 是同步写法, 但本质还是异步调用 。
即,只要遇到了 await ,后面的代码都相当于放在 callback 里。
forof
定时算乘法
执行 async 函数执行返回的是 Promise 对象
await 相当于 Promise 的 then
trycatch 可捕获异常,代替 Promise 的 catch
右上图解读: async返回Promise,await返回then,await后面报错会终止执行,可以用trycatch来捕获
以上就是关于swift 异步 async/await 的使用全部的内容,包括:swift 异步 async/await 的使用、记一次因@Async引发的程序bug、微信小程序退出账号怎么实现等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)