JavaScript异步

 JavaScript异步类型

  • 延迟类型:setTimeout、setInterval、setImmediate
  • 监听事件:监听new Image加载状态、监听script加载状态、监听iframe加载状态、Message
  • 带有异步功能类型: Promise、ajax、Worker、async/await

JavaScript常用异步编程

Promise

  Promise有几个特点:

  1. 对象的状态不受外界影响,有三种状态:pending(进行中)、fulfilled(成功)、rejected(失败)。只有异步操作的结果可以决定当前是哪种状态,其他操作无法改变。
  2. 状态一旦改变,就不会再变,任何时候都可以得到这个结果。状态改变只可能是:pending -> fulfilled 或 pending -> rejected
  3. 实例化后,会立即执行一次。所以一般将其用函数包裹起来,使用的时候调用一次。
  4. 如果执行后的回调也要做一些异步操作,可以无限的.then下去,当然要保证有返回值

  方法:

  • 原型方法 all race reject resolve
  • 对象方法 then catch finally(ES9)
function promiseTest(n,msg) {return new Promise((resolve,reject)=>{setTimeout(function () {console.log(`执行第${n}个任务`);msg.code && resolve(msg.text);  // 当认为成功的时候,调用resolve函数!msg.code && reject(msg.text);   // 当认为失败的时候,调用reject函数},n*500)});
}
let pro = promiseTest(1,{code:true,text:"返回的数据1"});
/* 没有catch,每个then里两个回调函数,此时第一个为成功的回调,第二个为失败的回调 */
pro.then((data)=>{console.log(data); // 执行成功结果在这里// return promiseTest(2,{code:true,text:"返回的数据2"});return promiseTest(2,{code:false,text:"失败的数据"});
},(err)=>{console.log(err); // 执行失败的结果在这里
}).then((data)=>{console.log(data)},(err)=>{console.log(err)});

观察then和catch的用法:

  • 在多次then后最后跟一个catch,可以捕获所有的异常
/* 多个then和一个catch */
pro.then((data)=>{console.log(data);return promiseTest(2,{code:false,text:"失败的数据"});
}).then((data)=>{console.log(data)
}).catch((err,data)=>{console.log("失败了",err);
});

all和rece的用法:

  • all接收一个promise对象列表.在所有异步操作执行完且全部成功的时候才执行then回调,只要有一个失败,就执行catch回调(只对第一个失败的promise对象执行)。
  • race也接收一个promise对象列表,不同的是,哪个最先执行完,对应的那个对象就执行then或catch方法(then或catch只执行一次)。
/* all的用法 */
Promise.all([promiseTest(1,{code:true,text:"返回的数据1"}),promiseTest(2,{code:false,text:"返回的数据2"}),promiseTest(3,{code:false,text:"返回的数据3"})
]).then((res)=>{console.log("全部成功",res)}).catch((err)=>{console.log("失败",err);});/* race的用法 */
Promise.race([promiseTest(1,{code:false,text:"返回的数据1"}),promiseTest(2,{code:false,text:"返回的数据2"}),promiseTest(3,{code:true,text:"返回的数据3"})
]).then((res)=>{console.log("成功",res)}).catch((err)=>{console.log("失败",err);});

Generator

Generator是什么?叫做生成器,通过function*关键字来定义的函数称之为生成器函数(generator function),与Python的语法一模一样

生成器有3个方法,都有一样的返回值{value,done}

  • .next(value)   value为向生成器传递的值。
  • .return(value) value为需要返回的值。该方法返回给定的值并结束生成器。
  • .throw(exception)  exception用于抛出的异常。该方法用来向生成器抛出异常,并恢复生成器的执行。

生成器的作用:

可以和 Promise 组合使用。减少代码量,写起来更方便。在没有Generator时,写Promise会需要很多的then,每个then内都有不同的处理逻辑。现在,我们将所有的逻辑写进一个生成器函数(或者在生成器函数内用yield 进行函数调用),Promise的每个then内调用同一个函数即可。

定义生成器:

function add(a,b) {console.log("+");return a+b;
}
function cut(a,b) {console.log("-");return a-b;
}
function mul(a,b) {console.log("*");return a*b;
}
function division(a,b) {console.log("/");return a/b;
}
function* compute(a, b) {yield add(a,b);yield cut(a,b);let value = yield mul(a,b);console.log("value",value); // 第三次调用.next()时无法为value赋值,需要第四次调用才能为其赋值yield mul(a,b);yield division(a,b);
}

使用生成器:

// 执行一下这个函数得到 Generator 实例,调用next()方法执行,遇到yield暂停
let generator = compute(4, 2);function promise() {return new Promise((resolve, reject) => {let res = generator.next();if(res.value > 5){resolve("OK");}else{reject("小于5")}});
}let proObj = promise();
proObj.then((data)=>{console.log(data);let res = generator.next();console.log("Promise res1",res);
}).then((data)=>{let res = generator.next();// let res = generator.return();console.log("Promise res2",res);
}).then((data)=>{let res = generator.next("qwe"); // 第四次next()时,向生成器传数据console.log("Promise res3",res)
}).catch((err)=>{console.log("出错",err);
});

async/await

优点:简洁,节约了不少代码

  • 被async修饰的函数,总会返回一个Promise对象。如果代码中返回值不是promise对象,它会将其包装成promise对象的resolved值
  • await只能在async函数内使用。它是一个操作符,等待一个函数或表达式。经过该操作符处理后,输出一个值。

如果在异步函数中,每个任务都需要上个任务的返回结果,可以这么做:

function takeLongTime(n) {return new Promise((resolve,reject) => {setTimeout(() => {resolve(n + 200)}, n);});
}function step1(n) {console.log(`step1 with ${n}`);return takeLongTime(n);
}function step2(m, n) {console.log(`step2 with ${m} and ${n}`);return takeLongTime(m + n);
}function step3(k, m, n) {console.log(`step3 with ${k}, ${m} and ${n}`);return takeLongTime(k + m + n);
}async function doIt() {console.time("doIt");const time1 = 300;const time2 = await step1(time1);const time3 = await step2(time1, time2);const result = await step3(time1, time2, time3);console.log(`result is ${result}`);console.timeEnd("doIt");
}
doIt();

如果这几个任务没有关联,可以这样做:

async function doIt() {  // 函数执行耗时2100msconsole.time("doIt");await step1(300).catch((err)=>{console.log(err)});  // 异常处理await step1(800);await step1(1000);console.timeEnd("doIt");
}
doIt();

当然,最好这样做:

async function doIt() { // 函数执行耗时1000msconsole.time("doIt");const time1Pro = step1(300);const time2Pro = step1(800);const time3Pro = step1(1000);await time1Pro;await time2Pro;await time3Pro;console.timeEnd("doIt");
}
doIt();

注意:

  1. async/await并没有脱离Promise,它的出现能够更好地协同Promise工作。
    • 怎么体现更好地协同?它替代了then catch的写法。使得等待promise值的操作更优雅,更容易阅读和书写。
  2. 函数仅仅加上async并没有意义,它仍然是同步函数,只有与await结合使用,它才会变成异步函数。
    • 这需要精准理解await。它在等待的时候并没有阻塞程序,此函数也不占用CPU资源,使得整个函数做到了异步执行。
  3. doIt()函数内部是串行执行的,但它本身是异步函数。
  4. 在这个异步函数内,可能会做很多操作ABC,他们有执行的先后顺序。这时你可能会想,A、B、C之间没有关联,他们之间可以是并行执行的,并不需要串行,那怎么办?
    • 【错误想法】这样想没错,但是没必要。因为他们已经存在于异步函数内了,所有的操作已经是异步的。在同样的环境情景下,底层执行的效率是相同的,并不见得因为A和B之间互相异步而提高效率。
    • 【正确想法】这样想是有必要的。参照两个doIt(),调用的函数返回promise对象,前者是依次生成promise对象(依次执行任务),依次等待返回结果。等待总时长取决于所有任务执行时间之和。后者则是同时生成promise对象(同时执行任务),依次等待。等待总时长取决于耗时最长的任务。后者的CPU运用率更高。
  5. 错误处理。最标准的方法是使用try...catch语句,但是它不仅会捕捉到promise的异常,还会将所有出现的异常捕获。因此,可以使用.catch,只会捕获promise相关的异常。

 

转载于:https://www.cnblogs.com/V587Chinese/p/11437051.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sublime配置与各种插件

本文转自:http://www.cnblogs.com/yyhh/p/4232063.html Sublime Text 3 安装Package Control 点击View -> Show Console 在下方命令行内,输入以下命令。 import urllib.request,os;pfPackage Control.sublime-package;ippsublime.installed_packages_…

把Sublime Text 2打造成一个轻量级Python的IDE

本文转自:http://blog.l1n3.net/python/sublime-text-to-python-ide/ 因为这段时间迷上了Python,所以想吧Sublime Text 2弄成一个Python的简易IDE,Python自带的IDLE简直太难用!!!! 配置Python环…

数据库表操作、数据类型及完整性约束

数据库表操作、数据类型及完整性约束 库操作补充 数据库命名规则: 可以由字母、数字、下划线、@、#、$区分大小写唯一性不能使用关键字如 create select不能单独使用数字最长128位表操作补充 #语法: create table 表名…

算法第一次作业

1.代码规范(由于日后可能会用C和Java,就找了两种) Google C代码规范:https://blog.csdn.net/freeking101/article/details/78930381 Ggoogle Jave代码规范:https://www.jianshu.com/p/4e50269037ed 2.《数学之美》读后…

Sublime Text官方文档 中英文版本

英文版本:http://docs.sublimetext.info/en/latest/index.html 中文翻译版本:http://sublime-text.readthedocs.org/en/latest/reference/build_systems.html

第99:真正理解拉格朗日乘子法和 KKT 条件

转载于:https://www.cnblogs.com/invisible2/p/11441485.html

有了CodinGame,玩着游戏就能学编程

本文转自:http://www.codingpy.com/article/learning-to-code-becomes-a-game/ 今天编程派向大家推荐一个有趣的编程练习平台,而它与其他平台的差异,就在于它将编程练习变成了一个个游戏。这个平台的名字叫CodinGame,是一家法国创…

第98:svd原理

SVD分解:任何矩阵都可以分解成第一行的形式,3个相乘。UV都是正交矩阵,中间的是奇异值。 3个相乘的形式可以拆分。即奇异值*第一行*第一列。在相加。 奇异值有时很小,在这种情况下,丢掉,可以减少计算量&…

Python学习(变量与字符串)

print()、input()、if/else就可以做一个简陋的游戏 print() # 打印函数,将信息打印出来input() # 将信息打印,并且要求输入一段话,并且把这段话。input函数,这个函数会将字符串显示在IDLE上,并且让用户输入信息&#…

第97:一文读懂协方差与协方差矩阵

转载于:https://www.cnblogs.com/invisible2/p/11442777.html

Python清屏小结

1. cmd–>python import os i os.system(cls) 2.通用的清屏 def cls(): print("\n"*100) 3.为idle增加一个清屏的扩展ClearWindow 首先下载clearwindow.py(点击可直接下载,不能下载的可以右键保存,格式为py结尾&#xff0…

设计模式之模板方法模式实战解析

本文微信公众号「AndroidTraveler」首发。 背景 最近在看《设计模式之禅》,为了能够更加深入的理解设计模式,达到学以致用。 这边记录一下自己的一些感受和看法,并结合具体代码实战来进行说明。 模板方法模式 但凡和设计模式挂上钩&#xff0…

LIBSVM在MATLAB中的使用及SVM最优参数选取示例代码

1. 参考网站: LIBSVM 库下载:http://www.csie.ntu.edu.tw/~cjlin/libsvm/ https://www.csie.ntu.edu.tw/~cjlin/libsvm/index.html?js1#svm-toy-js 视频: http://v.youku.com/v_showMini/id_XMjc2NTY3MzYw_ft_131.html 详解&#xff1…

Date类+DateFormat

Date 类 Date 表示特定的瞬间,精确到毫秒。 毫秒概念:1000毫秒1秒 毫秒的0点: System.currentTimeMillis() 返回值long类型参数 用于获取当前日期的毫秒值 时间的原点:公元1970年 一月一日,午夜0:00&#…

Random Forest 资源汇总(待续)

决策树 http://leijun00.github.io/2014/09/decision-tree/ http://leijun00.github.io/2014/10/decision-tree-2/ http://blog.csdn.net/suipingsp/article/details/41927247 http://blog.csdn.net/suipingsp/article/details/42264413 http://isilic.iteye.com/blog/184…

python 运行当前目录下的所有文件

查看当前目录下所有py文件(本身除外run) import osfile_list os.listdir(os.getcwd()) # 获取当前目录下所有的文件名print(file_list)for filename in file_list: if os.path.isfile(filename) and filename.endswith(.py) and filename.find(&quo…

第96:SVM简介与简单应用

详细推到见:https://blog.csdn.net/v_july_v/article/details/7624837 python实现方式: 转载于:https://www.cnblogs.com/invisible2/p/11448307.html

Matlab计算机视觉/图像处理工具箱(待续)

Matlab计算机视觉/图像处理工具箱推荐 http://blog.csdn.net/liuyue2046/article/details/12992139 VLFeat和Piotr’s Image & Video Matlab Toolbox http://blog.csdn.net/clheang/article/details/45640427

matlab如何把选中区域标亮

下面给出的是初始图像为彩色图像的情况。 %% Example on how to color select pixels in an image. % Kawahara (2013).% The original COLOR image. origImg imread(1.jpg); oldorigImg origImg; % Make sure the values are within 0-255. origImg uint8(origImg);% View…

Calendar是日历类

Calendar是日历类,在Date后出现,替换掉了许多Date的方法。该类将所有可能用到的时间信息封装为静态成员变量,方便获取。 Calendar为抽象类,由于语言敏感性,Calendar类在创建对象时并非直接创建,而是通过静态…