JavaScript 回调的心酸历程

发布于 2024-10-01 04:40:33 字数 4578 浏览 4 评论 0

运行前准备

npm i -g gulp bower

全局安装 gulp、bower。

  • gulp 是一个基于流的自动构建工具。
  • bower 是一个客户端技术的软件包管理器。

构建配置简述

gulpfile.js 文件是 gulp 的配置文件,类似 Gruntfile.js 和 webpack.config.js。

  • 使用 gulp-webserver 插件来运行本地的 Web 服务器与 LiveReload。
  • 使用 wiredep 插件将 bower 依赖的 css、js 自动插入到 html 页面中去

运行

  • npm i 安装 package.json 中依赖的 npm 包
  • bower install 安装 bower 依赖的包
  • gulp dev 执行此命令后会开启一个 web 服务,并自动打开浏览器。页面地址为 127.0.0.1:9000

需求

demo 中 src 文件里有 a、b、c 三个 json 文件,需求是我们需要依次请求它们,并且打印它们的值。

发展史

  • ES5 - 金字塔
  • ES6 - 链式
  • ES6 - 暂停
  • ES7 - 同步

ES5 - 金字塔

首先我们来到 ES5 的时代,为完成以上的需求写下如下的代码:

  $.ajax('./src/a.json').done((a)=>{

        console.log(a.data) // 打印 a 文件

        $.ajax('./src/a.json').done((b)=>{

              console.log(b.data)  // 打印 b 文件

              $.ajax('./src/a.json').done((c)=>{
                       console.log(c.data)  // 打印 c 文件
              })
        })
  })
  

嗯,也不错啊,一层套着一层,也算清晰明了了。如果当我们的需要改成 100 个文件的依次获取呢?此时,如果还这样写的话,那欢迎你来到 回调地狱

如果我们嵌套很多的代码,像金字塔一样的堆叠起来,不仅仅让代码显得更加难看、臃肿,也让项目变得越来越不好维护。

ES6 - 链式

我们来到了 ES6 的时代,这个时代的有个产物叫做 promise

通过 promise 我们可以将代码链式的调用改成如下的代码

function request(url){
	return new Promise((resolve, reject)=>{
		$.ajax(url).done((data)=>{
			resolve(data)
		}).fail((err)=>{
			reject(err)
		})
	})
}

request('./src/a.json').then((a)=>{
	console.log(a)
	return request('./src/b.json')
}).then((b)=>{
	console.log(b)
	return request('./src/c.json')
}).thne((c)=>{
	console.log(c)
})

相比 金字塔 式嵌套的代码,此时的代码更加的简洁,也更容易维护,但是也只不过是将嵌套改成了上下链接调用。

ES6 - 暂停

Generator 函数是 ES6 提供的一种异步编程解决方案,可以理解成内部有很多状态的状态机。

generator 函数与普通函数区别:

  • 定义的时候多了个 *
  • 函数内部使用 yield 来定义不同的状态
  • 调用的时候,需要将函数赋值给某个变量,每个变量之间的状态互不影响
  • 使用 next() 函数调用下一个状态
function request(url){
	$.ajax(url).done((data)=>{
		generator.next(data)
	})
}


function* generatorFn(){
	let a = yield request('./src/a.json')
	console.log(a)
	let b = yield request('./src/b.json')
	console.log(b)
	let c = yield request('./src/c.json')
	console.log(c)
}

var generator = generatorFn()

generator.next()

以上代码定义了 generatorFn 函数并赋值给 generator,在定义 request 函数的时候,当请求到数据的时候,调用 generator 的 next 方法。

ES7 async/await

万众瞩目,神器登场 async/await

先上代码:

(async () => {
	let a = await $.ajax('./src/a.json')
	console.log(a)
	let b = await $.ajax('./src/b.json')
	console.log(b)
	let c = await $.ajax('./src/c.json')
	console.log(c)
})

async 函数是 generator 函数的语法糖,只是将 * 变成了 async, yield 改成了 await ,但是代码却精简了这么多,它们直接的区别有以下几点:

  • async 函数不用手动去调用 next() 函数
  • async 函数返回值是 promise,generator 函数返回的是 Iterator

async 函数可以看成一个包含多个异步操作的 promise 的对象,await 就是 then 的语法糖。

四种方式中最精简的方式。使用 async 处理回调函数,代码会异常的清新,我们写起来也会很爽很舒服。

为什么会有这种感觉呢?

因为它是最符合我们写代码的习惯,用同步的写法去解决异步的代码。

换个 HTTP 库,这里使用 fetch 来实现

### generator

function getUrl(url){
	fetch(url).then((data)=>{
		generator.next(data.json())
	})	
}

function* test(){
	var a = yield getUrl('./src/a.json')
	aJson.then(data=>{
		console.log(data)
	})
}

var generator = test()
generator.next();

### async

(async ()=>{
	
	let a = await fetch('./src/a.json')
	let aJson = a.json()
	aJson.then((data)=>{
		console.log(data)
	})
})()

fetch(url),需要加上一句 response.json() 来从 response 流对象中获取数据,返回的是个 promise 对象。

Github 地址: https://github.com/Ortonzhang/js_callback

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

老街孤人

暂无简介

0 文章
0 评论
21 人气
更多

推荐作者

风暴

文章 0 评论 0

乐玩

文章 0 评论 0

英雄似剑

文章 0 评论 0

秋风の叶未落

文章 0 评论 0

luoshaoja

文章 0 评论 0

吴彦文

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文