js中的回调地狱 Callback to Hell
本文重点:解决方式:1.promise 2. 拆解 function:将各步拆解为单个的 function 3. 通过 Generator 函数暂停执行的效果方式 4. 通过ES8的异步函数 async / await
相关链接:promise详讲 https://www.cnblogs.com/sweeeper/p/8442613.html
开始进入Callback to Hell
必须知道的相关概念:
-
什么是回调地狱?(函数作为参数层层嵌套)
-
异步的JavaScript程序,或者说使用了回调函数的JavaScript程序,很难地去直观顺畅地阅读,,就是函数作为参数层层嵌套。代码以此种形式展现时无疑是不利于我们阅读与维护的。
-
什么是回调函数?(一个函数作为参数需要依赖另一个函数执行调用)
-
回调函数是必须得依赖另一个函数执行调用,它是异步执行的,也就是需要时间等待,典型的例子就是Ajax应用,比如http请求,在不刷新浏览器的情况下,当你执行DOM事件时,比如页面上点击某链接,回车等事件操作,浏览器会悄悄向服务端发送若干http请求,携带后台可识别的参数,等待服务器响应返回数据,这个过程是异步回调的,当许多功能需要连续调用,环环相扣依赖时,它就类似下面的代码,代码全部一层一层的嵌套,看起来就很庞大,很恶心,就产生了回调地狱.
-
如何解决回调地狱
-
保持你的代码简短(给函数取有意义的名字,见名知意,而非匿名函数,写成一大坨)
-
模块化(函数封装,打包,每个功能独立,可以单独的定义一个js文件Vue,react中通过import导入就是一种体现)
-
处理每一个错误
-
创建模块时的一些经验法则
-
承诺/生成器/ES6等
-
Promises:编写异步代码的一种方式,它仍然以自顶向下的方式执行,并且由于鼓励使用try / catch样式错误处理而处理更多类型的错误
-
Generators:生成器让你“暂停”单个函数,而不会暂停整个程序的状态,但代码要稍微复杂一些,以使代码看起来像自上而下地执行
-
Async functions:异步函数是一个建议的ES7功能,它将以更高级别的语法进一步包装生成器和继承
什么是“回调地狱”?
回调地狱的原因是,当人们试图以一种从上到下的视觉方式执行JavaScript的方式编写JavaScript时。很多人犯这个错误!在C,Ruby或Python等其他语言中,期望第1行发生的任何事情都会在第2行的代码开始运行之前完成,依此类推。
总结
回调地狱最主要的就是因为功能逻辑代码嵌套的层次太多,导致可读性降低,维护困难,避免回调地狱的最重要的方面是将功能移开,保持代码简单,不嵌套并分成小模块,也就是多多进行代码封装,将你所要的属性和方法用function关键字包裹起来,而且还要给它取一个有意义的名字,例如:页面上弹框,显示,隐藏,下拉等各个功能小模块,分别用有名函数给包裹起来,少用匿名函数,以便可以重复的多次使用,这也是可以便于程序流程的理解
除了常见的一种回调函数作为异步处理,还有promises,Generators,async是处理异步处理的方式,,关于这三个我也在学习当中,理论的东西虽是概念,没有大量代码的编写,个人觉得是很难理解这些东西,但是代码就是这些语言文字实实在在的转化,骚年们,加油,加油....
方法1: Promise 链式调用的方式 ES6
Promise是异步编程的一种解决方案, 比传统的解决方案--回调函数和事件更加强大. 没有Promise之前,解决异步都是依赖回调,但执行多个具备前后顺序的异步操作时代码就会非常乱并且出现问题难调试.
上面这只是简单的数据库查询操作,当操作多时就会回调中嵌着回调,所谓的回调地狱.
横向写代码变成了纵向,更加的直观,使用then进行下一步,代码清晰.
说一下Promise的基本用法, Promise有三种状态. 可以看下面的图片
Promise一旦新建就立刻执行, 此时的状态是Pending(进行中),它接受两个参数分别是resolve和reject.它们是两个函数.
resolve函数的作用是将Promise对象的状态从'未完成'变为'成功'(由Pending变为Resolved), 在异步操作成功时,将操作结果作为参数传递出去;
reject函数的作用是将Promise对象的状态从'未完成'变为失败(由Pending变为Rejected),在异步操作失败时调用,并将异步操作的错误作为参数传递出去.
Promise的用法
1.生成Promise实例
-
执行一系列同步操作3.使用resolve函数将异步操作的结果传递出去, reject函数传递异步操作的错误4.用then方法分别指定Resolve状态和Reject状态的函数,then方法返回一个新的Promise实例,因此可以采用链式写法
catch函数: 用于指定发生错误时的回调函数, 可以看成是 .then( null, reject() );当执行多个then操作时,建议用catch进行错误处理, 不用每个then函数都写一个reject的回调函数
catch回捕捉到前面执行时发生的错误.
Promise.all( 传入一个数组,每一项分别是一个Promise实例 ), 当数据里的Promise状态都变为resolve时, Promise.all状态才变为resolve
只要有一个Promise的状态变为reject, Promise.all就变为reject; 可以将数组里的Promise看成是 "与" 关系
Promise.race( 传入一个数组,每一项分别是Promise实例 ), 与Promise.all相反, race可以看到 是 "或" 关系, 只要有一个Promise状态变为resolve, Promise.all 就变为resolve
Promise.resolve(): 将现有对象转为Promise对象
(1) 参数是一个Promise实例的话,不做任何变动,返回原对象
(2) 参数是一个具有then方法的对象
Promise.resolve方法会将这个对象转为Promise对象, 然后立即执行该对象的then方法
(3) 参数不具有then方法, 或者根本不是对象. Promise.resolve方法返回一个新的Promise对象, 状态为Resolve
(4) 不带任何任何参数
Promise.resolve方法直接返回一个Resolve状态的Promise对象
Promise.reject(): 返回一个新的Promise实例,该实例状态为reject; 参数用法与Promise.resolve()方法完全一致
注意
Promise.resolve(返回的数据将成为下一个then函数中的参数)
Promise.resolve()
.then(function(){
//异步函数
}).then(function(){
//异步函数
})
方法2 拆解 function:将各步拆解为单个的 function
定时器中的回调函数处在外层函数中的作用域内,并通过参数传入,没有产生全局变量,没有重复代码。但是 function 拆分的方式其实仅仅只是拆分代码块,时常会不利于后续维护
方法3 通过 Generator 函数暂停执行的效果方式
通过 generator 虽然能提供较好的语法结构,但是毕竟 generator 与 yield 的语境用在这里多少还有些不太贴切
方法4. 通过ES8的异步函数 async / await
async 表示这是一个 async 函数,await 只能用在这个函数里面
await 表示在这里等待 Promise 返回结果后,再继续执行
await 后面跟着的应该是一个 Promise 对象(当然,其他返回值也没关系,只是会立即执行)
await 等待的虽然是 Promise 对象,但不必写 .then() ,可以直接得到返回值
通过写博客的方式,我想把对前端编程的感悟记录下来,回顾自己走过的路会对以后要走的路有所启示的。
如果你和我一样是初窥前端的一个怀抱梦想的初学者,我希望我走过的这段路能对你有些许的启示,让你对前端收获一点感悟。
如果你是一个前端的大牛,也由衷的希望你能留下些许的指教。
如果你和我一样是初窥前端的一个怀抱梦想的初学者,我希望我走过的这段路能对你有些许的启示,让你对前端收获一点感悟。
如果你是一个前端的大牛,也由衷的希望你能留下些许的指教。
posted on 2019-08-03 17:57 struggleForLife 阅读(411) 评论(0) 编辑 收藏 举报