c#的异步处理思路和vue前端中异步处理思路比较
前语:目前工作在做的项目是前端基于vue的组件式开发,通过api接口调用,后端数据逻辑是一个c#实现的WCF服务
1.总结自己在c# .NET 4.5后的新异步方式 async搭配await来实现 一个重要的类Task(这个和之前的Therad类很相似)
1.1 首先async是一个修饰符,它只能用在方法或者事件处理程序的签名中,对于方法的话可分为有无返回值两种情况,Task<TResult>可以作为返回值类型
举例:
private async Task Test_one_async() //这是一个无返回值的异步方法
private async Task<string> Test_two_async() //这是一个返回值类类型是string的异步方法
private async void Test_two_async() //这是一个异步事件处理程序
1.2 await是一个运算符,它表示等待异步执行的结果。也可以理解为await运算符实际上是对方法的返回值进行操作,也就是对Task<TResult>进行操作,而不是对方法本身进行操作。
举例:(当前业务需求是操作了DB后,对应更新系统中的某种缓存,我的写法如下,思路是操作完DB后异步去处理缓存,然后界面可以继续操作)
1 public Task<dynamic> doCacheMoudel(FormData formData)
2 {
3 string data;
4 formData.TryGetValue("data", out data);//这是参数转换
5 AjaxMessge msg = new AjaxMessge();
6 bool model = updateMoudelDB(data);//进行数据库更新操作
7 if (model)
8 {
9 msg.Set(MsgType.Success, "成功");
10 Task.Run(() => {
11 todoCacheInfo();//对应更新缓存的一个方法
12 });
13 }
14 else
15 {
16 msg.Set(MsgType.Error, "失败");
17 }
18 return GenRet.Msg(msg, "");
19 }
上面的适用于某些特定场景,有的场景需要利用async和await来解决,比如我们希望获取到更新的缓存所有数据,这时候就必须等到缓存更新完成后给我们返回这个数据,由于更新缓存的这个操作可能比较耗时,所以不能按照之前的那种同步思想,会造成UI界面卡顿现象,给客户的体验感不好。
1 public async Task<dynamic> doCacheMoudel(FormData formData)
2 {
3 string data;
4 formData.TryGetValue("data", out data);//这是参数转换
5 AjaxMessge msg = new AjaxMessge();
6 bool model = updateMoudelDB(data);//进行数据库更新操作
7 if (model)
8 {
9 Task<string> task1 = todoCacheInfo();
10 string value = await task1;//等待缓存更新后的返回值
11 msg.Set(MsgType.Success, value);
12 }
13 else
14 {
15 msg.Set(MsgType.Error, "");
16 }
17 return GenRet.Msg(msg, "");
18 }
这里后期发现我们的缓存更新需求又有了更改,在更新缓存完成后,需要处理和本次缓存更新有关的其他信息进行更新。通俗的说 A执行完成需要执行B,这里用await可以实现,还有一个就是Task的ContinueWith方法来实现
1 public async Task<string> todoThing() 2 { 3 /* 4 await doA();//执行A 5 doB();//A执行完成后才会执行B 6 */ 7 8 /* 9 string str1 = await doA();//获取A执行完的结果 10 doB();//获取A执行完的结果后执行B 11 */ 12 13 /* 14 await doA().ContinueWith(test => 15 { 16 doB();//A执行完后开始执行B,test为A的返回值 17 }); 18 */ 19 return ""; 20 } 21 private async Task<string> doA() 22 {
//todosomething() 23 return "A"; 24 } 25 private int doB() 26 {
//todo() 27 return 1; 28 }
以上学习的是异步的一个普遍使用方式,后面再vue的异步学习中发现有很多的类似的地方,如下:
2.vue中promise对象和异步思想(ES2017 标准引入了 async 函数,使得异步操作变得更加方便)
2.1 提一下,ES6 规定,Promise
对象是一个构造函数,用来生成Promise
实例,Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript 引擎提供,不用自己部署
具体作用大家可以看一下这个链接上的讲解
那么讲到async,一句话它就是 Generator 函数的语法糖,async函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
举例:
/** * 作用:通过code来拿到对应的name,然后把name进行操作 * @param {*} code */ async getMameByCode(code){
try{ let name = await getSystemName(code)//这个方法是进行了一个http请求,异步的 return name
}catch(err){
console.log(err)
} },
//async 方法是返回一个Promise对象,所以可以使用then方法来添加回调函数 getMameByCode('ABC').then(name=>{ //进行name操作 console.log(name) })
看起来是不是和前面c的异步思想和相似,async和await搭配使用,这里面需要注意的是:async
函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
同时正常情况下,await
命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。(这个还不太属性Promise对象的需要看看上面那个链接了),
当然,这个复杂的是错误处理机制了,我们需要知道的是,一旦异步操作出错后,Promise对象相当于被reject,那么异步函数后面的then回调不在触发,这时候需要用catch回调方法来接收当前错误信息,以便方法的不正常处理会被忽略。我们可以简单的理解一下,Promise的两个函数resolve和reject分别对应的是then和catch方法。
2.2 前面已经说过,await
命令后面的Promise
对象,运行结果可能是rejected
,所以最好把await
命令放在try...catch
代码块中,两种写法
async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); } } // 另一种写法 async function myFunction() { await somethingThatReturnsAPromise() .catch(function (err) { console.log(err); }); }
2.3 多个await
命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。举例;
//这是一个继发的动作,先执行完getFoo返回值后再执行getBar()方法 let foo = await getFoo(); let bar = await getBar(); //这个是并发的异步操作,getFoo()和 getBar()两个异步函数同时执行,没有相互依赖 let [foo, bar] = await Promise.all([getFoo(), getBar()]); // 这是第二种写法 let fooPromise = getFoo(); let barPromise = getBar(); let foo = await fooPromise; let bar = await barPromise;
目前说到的都是普遍较常用的异步处理,里面还有很多有趣的东西在学习之中,看到的朋友可以提意见帮助我改进,后面还有一篇随笔讲的是我对多个异步操作的同步处理思想以及并发进行,同步打印输出顺序的理解(个人认为比较有意思)