当前位置: 首页 > Web前端 > JavaScript

一个JSer的Dart学习日志(四):异步编程

时间:2023-03-26 23:06:21 JavaScript

本文是“一个JSer的Dart学习日志”系列文章的第四篇。本系列文章主要通过探究JS与Dart的异同,对JS进行回顾和巩固。同时顺利过渡到Dart语言。由于笔者还是Dart的初学者,所以理解可能是肤浅的、片面的。如果你有慧眼,还望指正。如无特殊说明,本文JS包含ES5到ES2021的所有特性,Dart版本为2.0及以上版本。Google最初开发Dart是作为JS的继承者,所以在设计上借鉴了很多JS的特性,比如事件驱动、单线程等,这使得它们的异步编程方式非常相似。一、使用回调函数的共同点JS和Dart都坚持“万物皆对象”的理念,函数也不例外。将函数作为参数传递以便在正确的时间调用它是最简单的异步编程解决方案。这里的A函数就是回调函数。>/**********************JS和Dart*********************/>varfunc=(param)=>param+1;>varcaller=(callback)=>callback(1);不同的是,Dart的异步流程与JS不同——它是阻塞的,单靠回调函数是无法解决问题的,所以回调式的异步接口是JS的标志(就这两种语言而言)。Dart-specific1.回调函数的类型定义函数时,回调函数是其参数之一,函数的参数可以声明类型,回调函数也不例外。但是,由于函数的元素较多,它不同于其他类型的声明——其他类型:type关键字在变量名前面:voidfunc(inta,Mapb){//做一点事}。函数类型:函数的类型是Function,但是声明参数类型为函数的语法不是Functioncallback://callback第一个参数是`num`类型,第二个参数是`int`类型//callback的返回值是`String`类型//如果这些类型没有显式声明,都是动态的voidfunc(Stringcallback(numa,intb)){//Dosomething}2.使用生成器函数ES6新增的Generator函数可以暂时中断执行,“唤醒”后继续执行。这个特性补充了异步过程,所以生成器函数也被用来处理异步过程。Dart中也有生成器函数,它们在概念上与JS生成器类似,但在语法和用法上有很多差异。常用1、使用*和yeild使用*声明一个生成器函数,使用yield关键字暂停该函数,并生成一个值。>/*JS*/|/*Dart*/>function*gen(max){|gen(intmax)sync*{>varstate=0;|varstate=0;>while(stateyieldstate++;|屈服状态++;>}|}>}|}>const读者=gen(6);|finalreader=gen(6);>console.log(reader.next().value);|print('${render.elementAt(0)}');>//0|//0生成器函数适用于一些重复触发调用的场景,比如WebSocket接口事件。2、“惰性”求值生成器函数的执行遇到yield就会停止,返回一个具体的对象,调用这个对象的具体方法,函数会继续运行,直到遇到下一个yield。区别1.Dart生成器分为同步和异步。JS只有一个生成器,返回的可迭代对象是生成器;Dart生成器分为同步(sync)和异步(async),同步生成器函数返回一个Iterator实例,异步生成器返回一个Stream实例。3.FutureVSPromise的共同点1.包装异步函数的返回值虽然异步编程历史悠久,但是异步函数是一个年轻的概念,所以在编程语言中引入异步函数的第一个问题是:如何将异步函数嵌入到同步逻辑流中?对于这个问题,JS给出的答案是Promise,相应地,Dart的答案是Future:>/*JS*/|//Dart>异步函数asyncFunc(){|asyncFunc()async{>returnawait'yes';|返回等待“是”;>}|}>console.log(asyncFunc());|print(asyncFunc());>//承诺{}|//Instanceof'_Future'2..then方法和链式调用方案都使用.then语法来订阅异步过程的最终结果:>/*JS*/|//Dart>asyncFunc().then(|asyncFunc().then(>(res)=>|(res)=>>console.log(`Got${res}`)|print('Got$res')>)|)>//是的|//是的。此外,.then方法还会返回一个新的Promise/Future。订阅这个返回值,获取回调函数的返回值(或者回调函数返回的Promise/Future包裹的值):>/*JS*/|//Dart>异步函数plus1(v=0){|intplus1(intv)async{>returnawaitv+1;|返回等待v+1;>}|}>函数plus2(v=0){|intplus2(intv){>返回v+2;|返回v+2;>}|}>plus1().then(plus1)|plus1().then(plus1)>.then(plus2).then(console.log);|.then(plus2).then(print);>//4|//4区别1.Dart类型注解在本系列文章中,Dart的这个特性是司空见惯的,Dart使用泛型语法约束Future的类型和它包装的值:Futurefooasync{return1;}2.Promise.allvsFuture.wait不知道是共同点还是不同点,因为语法完全一样,只是关键字不同:>/*JS*/|//Dart>Promise.all([|Future.wait([>plus1(),|plus1(),>plus1()|plus1()>]).then(|]).then(>()=>console.log('全部完成');|()=>print('全部完成');>);|);3。构造函数的参数不同,传入的函数参数形式也不同。两者都需要传入一个函数,只是这个函数的形式不同。Promise的执行器有两个位置参数:resolve和reject。Promise“包装”的值是resolve函数的返回值;Future的计算函数没有参数,Future包装的是计算的返回值。>/*JS*/|//Dart>consta=newPromise(|finala=/*new*/Future(>(resolve,reject)=>resolve(1)|()=>1>);|);>console.log(等待一个);|打印(等待一个);>//1|//1computation默认异步执行Promise。Excutor用来初始化Promise,JS的异步过程不会阻塞,所以是同步执行Future的计算直接用来取值,异步执行:>/*JS*/|//飞镖>varmut=0;|varmut=0;>consta=newPromise(|finala=/*new*/Future(>function(resolve,reject){|(){>mut++;|mut++;>resolve(1);|return1;>}|}>);|);>console.log(mut);|打印(mut);&g吨;//1|//0;如果你想同步执行计算,你应该使用命名构造函数Future.sync:intmut=0;finala=Future.sync((){mut++;returnmut;});打印(mut);//14.包装value和errorJS使用Promise.resolve(value)将value包装在Promise中,使用Promise.reject(error)包装errorerror;Dart的Future.value(value)和Future.error(error)分别实现了以上功能,其实我也不知道这两个包有什么用。5、Future承担更多的异步编程任务Future.delayedVSwindow.setTimeoutJS利用顶层对象提供的setTimeout接口来注册延迟任务,是回调式的接口;Dart使用命名构造函数Future.delayed来注册延迟任务:>/*JS*/|//Dart>vartask=setTimeout(|vartask=Future.delayed(>()=>{|Duration(milliseconds:100),>console.log('done');|(){>},|print('done');>100|}>};|};Dart使用Duration类来构造时间差,比JS中默认的毫秒直观多了(但是写起来有些繁琐,我不不知道有没有语法糖)。Future.microstackVSPromise.resolve().then在JS中注册微任务最方便的方案是Promise.resolve().then,(当然前提是使用runtime提供的Promise或者靠谱的polyfill方案),虽然“方便”,但毕竟只是个小把戏;而Dart提供了一个特殊的接口Future.microtask来注册微任务:>/*JS*/|//Dart>functionregister(task){|注册(任务){>承诺。resolve().then(|Future.microtask(>task|task>);|);>}|}幸运的是,大多数情况下,普通开发者并不需要开发者自己去调度任务优先级,所以JS这种写法无所谓,只要面试的时候不掉链即可。6.Promise有更多的功能。熟悉Promise的人不会对Promise.allSettle、Promise.race、Promise.any等静态方法感到陌生,而这些方法在Future中是没有的。我希望尽快在Dart中看到它们。给他们。JS终于扳回一局!4.async/await如果你问我ES6以来最喜欢哪个新特性,那无疑是ES2017带来的async/await语法和ES2015带来的解构语法。而在Dart中,async/await并没有缺席!7.Future是dart:async包提供的一个功能。如果你想使用Future(和),你应该首先导入dart:async包。但是,它可以在不导入Dartpad的情况下使用。相同的用法基本类似Talkischeap,这里是代码:>/*JS*/|//Dart>异步函数foo(){|foo()async{>returnawaitasyncFunc();|返回awaitasyncFunc();>}|}区别1.async关键字的位置在JS中,async放在函数声明语句之前;在Dart中,async放在函数参数列表之后。这种差异在上面的例子中已经体现出来了。TODO:需要对Dart构造函数初始化实例变量时将async放在哪里做一些研究。所以这里总结的立场不一定正确。2、分别返回Promise和Future在JS中,async函数返回一个Promise实例;在Dart中,异步函数返回一个Future实例。这两类的区别在上一节已经讲清楚了(至少作者自己认为讲清楚了),这里不再赘述。