博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript异步编程方案汇总剖析
阅读量:4566 次
发布时间:2019-06-08

本文共 5658 字,大约阅读时间需要 18 分钟。

js-async-demos

目录结构:

|—— 回调函数

|—— 事件监听

|—— 发布/订阅

|—— promise

|—— generator(es6生产函数)

|—— async(es7异步函数)

|—— 其他

|—— Rxjs(Observable对象)

此demo项目仅作为个人对js整个异步编程发展的总结汇总,遂参考了多方资料,已在末尾备注

asynchronous development process of javascript and some demos

回调函数callback

回调函数即函数的某个参数为function,会掉函数在拿到上一步结果后执行,如:

funa(param1, callback){
.... callback(xxx);}
▶︎
all
running...
 

事件监听

采用事件驱动模式,任务的执行不取决代码的顺序,而取决于某一个事件是否发生。

监听函数有:on,bind,listen,addEventListener,observe

// 为f1绑定一个事件(采用jquery写法)。当f1发生done事件,就执行f2。f1.on('done',f2);// 对f1进行改写, 执行完成后,立即触发done事件,从而开始执行f2.function f1(){
settimeout(function(){
//f1的任务代码 f1.trigger('done'); },1000);}f1.trigger('done')
▶︎
all
running...
 

这种方法的优点:比较容易理解,可以绑定多个事件,每一个事件可以指定多个回调函数,而且可以去耦合,有利于实现模块化。

这种方法的缺点:整个程序都要变成事件驱动型,运行流程会变得不清晰。
事件监听方法:
(1)onclick方法

element.onclick=function(){
//处理函数}
▶︎
all
running...
 

优点:写法兼容到主流浏览器

缺点:当同一个element元素绑定多个事件时,只有最后一个事件会被添加,例如:

// 只有handler3会被添加执行,所以我们使用另外一种方法添加事件element.onclick=handler1;element.onclick=handler2;element.onclick=handler3;
▶︎
all
running...
 

(2)attachEvent和addEvenListener方法

// IE:attachEvent 三个方法执行顺序:3-2-1elment.attachEvent("onclick",handler1);elment.attachEvent("onclick",handler2);elment.attachEvent("onclick",handler3);//标准addEventListener 执行顺序:1-2-3;elment.addEvenListener("click",handler1,false);elment.addEvenListener("click",handler2,false);elment.addEvenListener("click",handler3,false);
▶︎
all
running...
 

(三)DOM方法addEventListener()和removeListenner()

addEventListenner()和removeListenner()表示用来分配和删除事件的函数。这两种方法都需要三种参数,分别为:string(事件名称),要触发事件的函数function,指定事件的处理函数的时期或者阶段(boolean),例子见(二).

(四)通用的事件添加方法:

on:function(elment,type,handler){
//添加事件 return element.attachEvent?elment.attachEvent("on"+type,handler):elment.addEventListener(type,handler,false);}
▶︎
all
running...
 

发布/订阅

我们假定,存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”(publish)一个信号,其他任务可以向信号中心”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做”发布/订阅模式“(publish-subscribe pattern),又称”观察者模式“(observer pattern)。

这个模式有多种实现,下面采用的是Ben Alman的Tiny Pub/Sub,这是jQuery的一个插件。

首先,f2向”信号中心”jQuery订阅”done”信号。

jQuery.subscribe("done", f2);//然后,f1进行如下改写:function f1(){
  setTimeout(function () {
    // f1的任务代码    jQuery.publish("done");  }, 1000);}
▶︎
all
running...
 

jQuery.publish("done")的意思是,f1执行完成后,向”信号中心”jQuery发布”done”信号,从而引发f2的执行。

此外,f2完成执行后,也可以取消订阅(unsubscribe)。

jQuery.unsubscribe("done", f2);
▶︎
all
running...
 

这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

promise对象

Promise的概念并不是ES6新出的,而是ES6整合了一套新的写法。同样继续上面的例子,使用Promise代码就变成这样了:

/* promise的api方法: * promise construct * then * resolve/reject * catch * all * race: 顾名思义,Promse.race就是赛跑的意思,意思就是Promise.race([p1, p2, p3])里面哪个结果获得的快就返回那个结果 * finally: */var readFile = require('fs-readfile-promise');readFile(fileA).then((data)=>{
console.log(data)}).then(()=>{
return readFile(fileB)}).then((data)=>{
console.log(data)})// ... 读取n次.catch((err)=>{
console.log(err)})// 注意:上面代码使用了Node封装好的Promise版本的readFile函数,它的原理其实就是返回一个Promise对象,咱也简单地写一个:var fs = require('fs');var readFile = function(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) reject(err) resolve(data) }) })}module.export = readFile
▶︎
all
running...
 

但是,Promise的写法只是回调函数的改进,使用then()之后,异步任务的两段执行看得更清楚,除此之外并无新意。撇开优点,Promise的最大问题就是代码冗余,原来的任务被Promise包装一下,不管什么操作,一眼看上去都是一堆then(),原本的语意变得很不清楚。

Generator(from es6)

Generator(生成器)函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。ES6将JavaScript异步编程带入了一个全新的阶段。

Generator 函数的暂停执行的效果,意味着可以把异步操作写在yield表达式里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield表达式下面

generator函数的特性如下,后面两个特性使它可以作为异步编程的完整解决方案:

  • 暂停执行

  • 恢复执行

  • 函数体内外的数据交换

  • 错误处理机制

// Ajax是典型的异步操作,通过Generator函数部署Ajax操作,可以用同步的方式表达。function* main() {
var result = yield request("http://some.url"); var resp = JSON.parse(result); console.log(resp.value);}function request(url) {
makeAjaxCall(url, function(response){
it.next(response); });}var it = main();it.next();// 上面代码的main函数,就是通过 Ajax 操作获取数据。可以看到,除了多了一个yield,它几乎与同步操作的写法完全一样。注意,makeAjaxCall函数中的next方法,必须加上response参数,因为yield表达式,本身是没有值的,总是等于undefined。
▶︎
all
running...
 

async函数

ES2017标准引入了async函数,使得异步操作变得更加方便。但它其实是是Generator函数的语法糖

// demo1: 一个 Generator 函数,依次读取两个文件。const fs = require('fs');const readFile = function (fileName) {
return new Promise(function (resolve, reject) {
fs.readFile(fileName, function(error, data) {
if (error) return reject(error); resolve(data); }); });};const gen = function* () {
const f1 = yield readFile('/etc/fstab'); const f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString());};// 写成async函数,就是下面这样。// 比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab'); const f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString());};// demo2:async function getStockPriceByName(name) {
const symbol = await getStockSymbol(name); const stockPrice = await getStockPrice(symbol); return stockPrice;}getStockPriceByName('goog').then(function (result) {
console.log(result);});
▶︎
all
running...
 

async函数对 Generator 函数的改进,体现在以下四点。

  • 内置执行器

  • 更好的语义

  • 更广的适用性

  • 返回值是Promise

async 函数的实现原理:

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里

async function fn(args) {
// ...}// 等同于function fn(args) {
return spawn(function* () {
// ... });}
▶︎
all
running...
 

其他

RxJS

概述:Observable对象格式

参考文章&感谢

89

转载于:https://www.cnblogs.com/xudengwei/p/9024930.html

你可能感兴趣的文章
全局变量、局部变量、静态全局变量、静态局部变量的区别
查看>>
一道面试题及扩展
查看>>
Unity 3D 我来了
查看>>
setup elk with docker-compose
查看>>
C++ GUI Qt4学习笔记03
查看>>
Java基础回顾 —反射机制
查看>>
c# 前台js 调用后台代码
查看>>
2017-02-20 可编辑div中如何在光标位置添加内容
查看>>
$.ajax()方法详解
查看>>
day42
查看>>
jquery操作select(增加,删除,清空)
查看>>
Sublimetext3安装Emmet插件步骤
查看>>
MySQL配置参数
查看>>
全面理解Java内存模型
查看>>
A - Mike and palindrome
查看>>
DOTween教程
查看>>
java web中java和python混合使用
查看>>
创建学员类和教员类
查看>>
Cookie和Session的作用和工作原理
查看>>
字符串操作
查看>>