深入浅出写一个多级异步回调从基础到Promise实现的Demo
今天一时兴起,写了一个渐进升级的异步调用demo,记录一下。
1. 最基础的同步调用
//需求:f2在f1之后执行,且依赖f1的返回值。如下:
function f1(){
var s="1";
return s;
}
function f2(s){
s+="-2";
console.log(s);
}
f2(f1()); //"1-2"
2. 引入异步回调
//继续,如果f1是个耗时操作,业务上需要做成异步,那么就需要引入回调,如下:
function f1(){
var s;
setTimeout(function(){
s="1";
f2(s);
},1000);
}
function f2(s){
s+="-2";
console.log(s);
}
f1(); //"1-2"
3. 回调函数名解耦
//对上面代码,对f2做个函数名上的解耦,如下:
function f1(callback){
var s;
setTimeout(function(){
s="1";
callback(s);
},1000);
}
function f2(s){
s+="-2";
console.log(s);
}
f1(f2); //"1-2" //这样,不管以后f2的function name如何变更,我们都不需要去f1里修改对他的引用了
4. 更多层级的异步回调
//那么,我们继续,如果业务中引入了f3,且逐级依赖异步耗时操作f1和f2。如下:
function f1(){
var s;
setTimeout(function(){
s="1";
f2(s);
},1000);
}
function f2(s){
setTimeout(function(){
s+="-2";
f3(s);
},1000);
}
function f3(s){
s+="-3";
console.log(s);
}
f1(); //"1-2-3"
//这时,该怎么对f2和f3的function name解耦,以及怎样保持一个类似f1().f2().f3()样子的清晰的调用呢?
4.1 试着优雅一点
//思来想去,看起来需要引入更多的传参,那搞两个callback参数吧:
function f1(callback1,callback2){
var s;
setTimeout(function(){
s="1";
callback1(s,callback2);
},1000);
}
function f2(s,callback){
setTimeout(function(){
s+="-2";
callback(s);
},1000);
}
function f3(s){
s+="-3";
console.log(s);
}
f1(f2,f3); //"1-2-3"
//WTF,尼玛,这也太尼玛脏了。函数名虽然解耦了,调用也很清晰。但是一个callback2参数需要在多个function之间传递,代码可读性变差;并且f1中传入了并不需要处理的callback2,逻辑有些冗余。
5. 观察者模式拉平回调
重新思考下,看起来逐级依赖的函数回调,随着层级的加深,在传参和调用上都越来越吃力了。
我们现在想办法拉平一下这些回调,用自定义事件改造下。
专业术语上,叫观察者模式,即通过自定义事件的监听和触发,来实现函数的依赖调用(f1触发f2的调用)
//注册自定义事件 拆解f1 f2 f3的依赖回调关系导致的代码逻辑上的嵌套(使用CustomEvent的detail属性,实现参数传递)
document.addEventListener("f1:done",function(e){
f2(e.detail);
});
document.addEventListener("f2:done",function(e){
f3(e.detail);
}); function f1(){
var s;
setTimeout(function(){
s="1";
document.dispatchEvent(new CustomEvent('f1:done', {detail:s}));
},1000); }
function f2(s){
setTimeout(function(){
s+="-2";
document.dispatchEvent(new CustomEvent('f2:done', {detail:s}));
},1000);
}
function f3(s){
s+="-3";
console.log(s);
} f1(); //"1-2-3"
注:阮一峰的这篇文章里,还引入了一个订阅/发布模式,个人感觉没什么意义,核心原理还是事件注册,参考:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
6. Promise的实现
上面的观察者模式,看起来比较优雅了,但是因为拉平几个有依赖关系的回调函数,就去注册一些自定义事件,还是感觉有点怪。
并且,在调用上,只是写了一个f1(),并不能在调用上看出三个函数的依赖关系。
ES6开始,引入了Promise概念,专门用来处理异步操作问题,参考:http://es6.ruanyifeng.com/#docs/promise
//继续Promise方式,试着改写一下: function f1(){
var p1=new Promise(function(resolve, reject) {
var s;
setTimeout(function(){
s="1";
resolve(s);
},1000); });
return p1;
}
function f2(s){
var p2=new Promise(function(resolve, reject) {
setTimeout(function(){
s+="-2";
resolve(s);
},1000); });
return p2;
}
function f3(s){
s+="-3";
console.log(s);
} f1().then(function(s) {
return f2(s);
}).then(function(s) {
f3(s);
}) //看起来,还不错哦
深入浅出写一个多级异步回调从基础到Promise实现的Demo的更多相关文章
- js异步回调Async/Await与Promise区别 新学习使用Async/Await
Promise,我们了解到promise是ES6为解决异步回调而生,避免出现这种回调地狱,那么为何又需要Async/Await呢?你是不是和我一样对Async/Await感兴趣以及想知道如何使用,下面 ...
- nodeJS+express+Jade写一个局域网聊天应用(node基础)
为了复习一下nodeJS, 而且socketIO这东西听起来就好高端有木有, 而且有人写过了open, 也可以作为自己的参考有木有, 点击下载源代码: express是4.x的版本, 跟以前的配置有些 ...
- Jmeter使用基础笔记-写一个http请求
前言 本篇文章主要讲述2个部分: 搭建一个简单的测试环境 用Jmeter发送一个简单的http请求 搭建测试环境 编写flask代码(我参考了开源项目HttpRunner的测试服务器),将如下的代码保 ...
- 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise
本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...
- 并发编程 —— 自己写一个异步回调 API
1. 前言 在并发编程中,异步回调的效率不言而喻,在业务开发中,如果由阻塞的任务需要执行,必然要使用异步线程.并且,如果我们想在异步执行之后,根据他的结果执行一些动作. JDK 8 之前的 Futur ...
- 深入浅出React Native 3: 从零开始写一个Hello World
这是深入浅出React Native的第三篇文章. 1. 环境配置 2. 我的第一个应用 将index.ios.js中的代码全部删掉,为什么要删掉呢?因为我们准备从零开始写一个应用~学习技术最好的方式 ...
- 用C写一个web服务器(一) 基础功能
.container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...
- C#基础:线程之异步回调(委托)
异步回调,什么是异步回调?我是这样理解的,当主线程在执行一段代码的时候,我们用委托执行了一个线程,这个线程要返回一个结果,关键是什么时候返回这个结果,异步回调就是在这个线程执行完成后立即返回这个线程的 ...
- Java基础-接口.编写2个接口:InterfaceA和InterfaceB;在接口InterfaceA中有个方法void printCapitalLetter();在接口InterfaceB中有个方法void printLowercaseLetter();然 后写一个类Print实现接口InterfaceA和InterfaceB,要求 方法 实现输出大写英文字母表的功能,printLowerca
#34.编写2个接口:InterfaceA和InterfaceB:在接口InterfaceA中有个方法void printCapitalLetter():在接口InterfaceB中有个方法void ...
随机推荐
- vue之事件处理
一.事件处理方法 1.格式 完整格式:v-on:事件名="函数名" 或 v-on:事件名="函数名(参数……)" 缩写格式:@事件名="函数名&qu ...
- 佳佳的 Fibonacci
佳佳的 Fibonacci \(f_n=f_{n-1}+f_{n-2},f_1=f_2=1\),求\(f_1+2f_2+3f_3+...+nf_nmod\ m,1≤n,m≤2^{31}-1\). 解 ...
- 小程序登录时如何获取input框中的内容
最近写小程序项目遇到一些问题,今天整理下这些问题的解决方法,希望对用户有帮助.下面是登录页,点击登录时获取input框中的值, 效果如下: wxml布局如下: <view > <in ...
- Q:简单实现URL只能页面跳转,禁止直接访问
sessionStorage 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据,且不同标签页的session不能共享,通过此特性来控制某个页面只能通过上级页面同标签页跳转 ...
- elementui tree 节点过滤加载对应子节点
/官网例子 <el-input placeholder="输入关键字进行过滤" v-model="filterText"> </el-inpu ...
- Spring随笔-bean装配
Spring提供了三种装配方式 1.XML文件进行显式装配 2.java中进行显示装配 3.自动化装配 1.自动化装配的两种实现方式 1.组件扫描:Spring会自动发现应用上下文中创建的bean 2 ...
- 【Web】浅析JQuery的apply(), call(), bind()方法
原文地址:https://blog.csdn.net/whuzxq/article/details/64166253 由于在理解this的用法的时候多次出现了这几个方法,个人对这几个方法理解的不是很透 ...
- 金三银四铜五铁六,Offer收到手软!
作者:鲁班大师 来源:cnblogs.com/zhuoqingsen/p/interview.html 文中的鲁班简称LB 据说,金三银四,截止今天为止面试黄金时间已经过去十之八九,而LB恰逢是这批面 ...
- sklearn算法中的顶层设计
sklearn监督学习的各个模块 neighbors近邻算法,svm支持向量机,kernal_ridge核岭回归,discriminant_analysis判别分析,linear_model广义线性模 ...
- 【ASP.Net Core】不编译视图文件
原文:[ASP.Net Core]不编译视图文件 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/aqtata/article/details/818 ...