ES6中Promise可以说很大情况下改善了异步回调的嵌套问题,那么如果我们自己去写一个类似Promise的库应该怎么去写?

  我们先看一下Promise的特点:

  第一:Promise构造函数接受一个函数作为参数,函数里面有两个参数resolve和reject分别作为执行成功或者执行失败的函数

var promise=new Promsie(function(resolve,rejec){
if(/*异步执行成功*/){
resolve(value);
}else{
reject(error);
}
})

  第二:可以通过then设置操作成功之后的操作,接受两个函数作为参数

.then(function(){
//回调执行成功之后的操作
},function(){
//回调执行失败之后的操作,可以没有
});

  那么原生js实现以上特点应该比较简单了

function PromiseM(){
this.status='pending';
this.msg='';
var process=arguments[];
var that=this;
process(function(){
that.status='resolve';
that.msg=arguments[];
},function(){
that.status='reject';
that.msg=arguments[];
});
return this;
}
PromiseM.prototype.then=function(){
if(this.status=='resolve'){
arguments[](this.msg);
}
if(this.status=='reject'&&arguments[]){
arguments[](this.msg);
}
}
//测试用例
var mm=new PromiseM(function(resolve,reject){
resolve('123');//123其实就是第二个arguments[0]
});//上面的第一个arguments[0]
mm.then(function(success){
console.log(success);//该success其实就是上面的this.msg
console.log("ok!");
},function(){
console.log('fail!');
});
//123
//ok

  以上只是最基本的实现,在代码结构结构和容错方面没有进行考虑。

  对ES6里promise对象以及异步机制的理解

  我现在声明一个a,并且要延时1秒钟后给他赋值为10,然后打印这个a:

var a;
setTimeout(function (){
a = ;
},);//1000ms后给a赋值为10
console.log(a)//undefined,

  很显然,a是undefined,因为js是非阻塞的,它不会等你定时器里的东西走完了,再执行打印a这个操作。它不等你读完,就会迫不及待地去打印a,因为a要1秒后才能被赋值,所以此时a只是个undefined。

  那怎么办?很简单,把打印a这个操作也放进延时定时器里嘛,我想这个例子并不难理解,那么接下来我会试图将其功能进行拓展,打印a这个需求我并不需要,我想要用a做其他事情,比如让他乘以2并输出返回结果,或者其他的涉及到a的操作。那很简单,我将console.log(a)这段代码删去,封装成一个函数,并将其作为参数传进这个定时器里,也就是所谓的“回调函数”如下:

var a;
function foo(callBack){
setTimeout(function (){
    a = 10;
    callBack&&callBack()
  },)
} foo(function (){ //因为a是全局的,所以不需要将a传参进foo的回调中
  return a*
})

  调用foo的时候,作为参数的这个匿名函数,就是所谓的回调函数,回调函数这个机制极大地增加了代码的可能性,你可以在回调中做任何事,并且在不同的地方进行调用,你也将得到不同的反馈,如果将一个函数执行过程看成一个时间轴,那回调函数就可以允许你在这个过程中的各个时刻内执行其他代码,例如你可以将Vue.js的生命周期钩子函数看成是不同时期的回调函数

  回调函数的作用显而易见,但如果一层回调套一层回调的话,代码极其不方便阅读与修改,因此ES6提供了Promise构造函数,从形式上改善了回调地狱。

var a;
var p = new Promise(function (resolve,reject){
  setTimeout(function (){
    a = ;
    resolve();/*reject也就是失败时对应的函数,由于这个例子比较简单,就不再赘述,毕竟是面向新手的*/
  },)
}).then(function (){
  console.log(a)
})

  现在我们就以一个人起床后的行为为例来深入理解异步执行机制,来看代码:

getup();
wearClothes();
brushTeeth();
washFace();
eatBreakfast();
goToCompany();

  因为js是异步执行的,所以如果这么写,逻辑上等同于一个人同时开始做“起床+穿衣+刷牙+洗脸+吃早饭+出门上班”这些事,显然是不可能的事情,与我们想要的结果大相径庭,依照回调函数的写法,我们会在上述每个行为结束之后(即函数执行完毕的我们想要让他做什么,例如$.ajax()的success)传入一个回调函数,并将下一步的函数写进回调里,环环相扣,写法比较恶心,相当难以维护。

var p = new Promise(function (resolve){
getUp(function (){
resolve();
});
}).then(function (){
return new Promise(function (resolve){
wearClothes(function (){
resolve();
});
})
}).then(function (){
return new Promise(function (resolve){
brushTeeth(function (){
resolve();
});
})
}).then(function (){
return new Promise(function (resolve){
washFace(function (){
resolve();
});
})
}).then(function (){
return new Promise(function (resolve){
eatBreakfast(function (){
resolve();
});
})
}).then(function (){
goToCompany()
})

  如果要链式调用then的话,必须要注意的一点是,一定要在then里的回调函数return一个新的promise对象,否则执行顺序将向上开始查找,直到找到最近的promise实例。

  写到这里大家会发现promise并没有改变什么,只是把异步代码的书写形式从水平方向改为了竖直方向,让代码更符合人类的阅读习惯

原生JS实现Promise的更多相关文章

  1. 原生js实现canvas气泡冒泡效果

    说明: 本文章主要分为ES5和ES6两个版本 ES5版本是早期版本,后面用ES6重写优化的,建议使用ES6版本. 1, 原生js实现canvas气泡冒泡效果的插件,api丰富,使用简单2, 只需引入J ...

  2. 【面试篇】寒冬求职季之你必须要懂的原生JS(中)

    互联网寒冬之际,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更多的努力. 一年前,也许你搞清楚闭包,this,原型链,就能获得认可.但是现在 ...

  3. 原生js替换jQuery各种方法-中文版

    原文https://github.com/nefe/You-D... 原生JS与jQuery操作DOM对比 You Don't Need jQuery 前端发展很快,现代浏览器原生 API 已经足够好 ...

  4. 用原生js写一个"多动症"的简历

    用原生js写一个"多动症"的简历 预览地址源码地址 最近在知乎上看到@方应杭用vue写了一个会动的简历,觉得挺好玩的,研究一下其实现思路,决定试试用原生js来实现. 会动的简历实现 ...

  5. 基于原生JS实现的Bean容器和AOP编程

    Bean是什么 我们知道Bean是Spring最基础的核心构件,大多数逻辑代码都通过Bean进行管理.NestJS基于TypeScript和依赖注入也实现了类似于Spring Bean的机制:服务提供 ...

  6. 原生JS封装Ajax插件(同域&&jsonp跨域)

    抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...

  7. 常用原生JS方法总结(兼容性写法)

    经常会用到原生JS来写前端...但是原生JS的一些方法在适应各个浏览器的时候写法有的也不怎么一样的... 今天下班有点累... 就来总结一下简单的东西吧…… 备注:一下的方法都是包裹在一个EventU ...

  8. 原生JS实现"旋转木马"效果的图片轮播插件

    一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...

  9. 再谈React.js实现原生js拖拽效果

    前几天写的那个拖拽,自己留下的疑问...这次在热心博友的提示下又修正了一些小小的bug,也加了拖拽的边缘检测部分...就再聊聊拖拽吧 一.不要直接操作dom元素 react中使用了虚拟dom的概念,目 ...

随机推荐

  1. Nginx增加模块

    http://blog.csdn.net/loyachen/article/details/50902667

  2. 七层负载(Application Gateway)+四层负载(LB)

    上次有个电商客户需要搭建如架构. 192.168.1.100/url1(请求url)——>Node1:10.0.0.4.10.0.0.5(服务器IP) 192.168.1.100/url2(请求 ...

  3. 移动前端开发和 Web 前端开发的区别是什么

    可以分成两部分理解1.服务器端开发,也叫后台开发,这是唯一的,对应不同的平台,他负责数据的分发与存储,和一些逻辑的处理.逻辑处理的多少由业务的复杂程度决定.服务端相对独立,与平台没啥关系. 2..1中 ...

  4. Cortex-M4 Core Registers

    Cortex-M4 Core Registers Goal: visualizing what happens to the Cortex-M4 core registers after reset ...

  5. The STM32 SPI and FPGA communication

    The STM32 SPI and FPGA communication STM32 spi bus communication SPI bus in the study, the protocol ...

  6. MUI框架之输入框Input

    input输入框的官方api文档:http://dev.dcloud.net.cn/mui/ui/#input 一.输入框类型 输入框的类型是根据type来决定是普通输入框还是密码框,搜索框等类型 & ...

  7. ASP.NET Web Pages 的冲突版本问题

    随着VS版本和.NET MVC版本.EF的版本的不断更新,虽然很多功能随着版本的提升而更完善,但对于旧版本开发的软件就有点悲催了,或许很多开发者都遇到类似的问题! 最近有一个项目是用.NET MVC3 ...

  8. maria-developers 开发者邮件

    https://lists.launchpad.net/maria-developers/

  9. 解决winform中mdi子窗体加载时显示最大化最小化按钮的方法

    场景:在mid加载子窗体的时候如果指定WindowState为Maximized,加载完成后主窗体会显示最大化.最小化.关闭的按钮图标. 解决方法: 1.更改主窗体FormMain的属性.制定Main ...

  10. 无法打开物理文件 XXX.mdf",操作系统错误 5:"5(拒绝访问。)"的解决办法

    http://blog.csdn.net/blackfield/article/details/6550499 用T-SQL命令附加数据库时,出现如下异常信息: 无法打开物理文件 XXX.mdf&qu ...