一、先看一个应用场景

  发送一个请求获得用户id, 然后根据所获得的用户id去执行另外处理。当然这里我们完全可以使用回调,即在请求成功之后执行callback;

但是如果又添加需求呢?比如获得用户id之后,再发送请求去获取用户名,之后再获取用户其他信息。。。。这就陷入了callback-hell,而且代码很难维护。promise可以解决这样的问题。

function getUserId() {
return new Promise(function(resolve) {
//异步请求
http.get(url, function(res) {
resolve(res.id)
})
})
} getUserId().then(function(id) {
//其他处理
})

上面的回调是不是看起来不叫顺手了。 

 

二、Promise是什么?

它简单说就是一个容器,就是一个构造函数。里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

也可以说Promise 是异步编程的一种解决方案,其实我们经常使用$.ajax()就是一种promise的解决方案

更加详细的内容可以看阮一峰的《Promise对象》

三、can i use 

现在更多的浏览器对Promise提供了原生的支持。axios基于 Promise 的 HTTP 请求就是一个常用的应用栗子。

三、写点demo

当对概念有点燃的时候,回头看看自己写过的demo,肯定有不一样的理解,这即是博客的一个好处之一

function getNumber(){
return new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10);
if(num<=5){
resolve(num);
}
else{
reject('num的值大了');
}
}, 2000);
});
} getNumber()
.then(function(data){
console.log('resolved');
console.dir(data);
})
.catch(function(data){
console.log('rejected');
console.dir(data);
});

  

封装一个函数,参数是定时器的时间参数

 function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
sleep(5000).then(function(val){
  console.log(`${val}秒之后起床`);
});

四、怎么实现一个promise?  

1、最简单的promise雏形

function Promise(fn){

        if(fn && typeof fn !== 'function'){ throw new Error('Promise resolver is not a function') };
//回调函数数组,肯能同时有多个回调
this.callBacks = []; //执行函数
const resolve = val =>{
//执行全部回调
setTimeout(()=>{
this.callBacks.forEach(cb=>{
cb(val)
});
},0)
};
//将resolve作为实参传入fn中,fn的异步什么时候有结果再去执行resolve
fn(resolve);
} //注册回调函数,successCallback将会被压进Promise容器中的callBacks队列
Promise.prototype.then = function(successCallback){
this.callBacks.push(successCallback);
}; //测试用例
const promise = new Promise(function(resolve){
//模拟一个异步
setTimeout(()=>{
resolve('我是传给Promise内执行函数的参数')
},2000)
}) promise.then(function(val){
console.log(val);
});

  

说明:
(1)、创建promise实例时候传进的函数函数被赋予一个函数类型的参数resolve,resolve接收一个参数,代表异步但返回的结果;当异步操作成功之后,就会执行resolve方法;
(2)、调用then方法,将想要在Promise异步操作成功时执行的回调放入callBacks队列,其实也就是注册回调函数,
(3)、第一步中执行resolve方法就就是执行callbacks数组中的回调函数,依次执行;
(4)、加入延迟机制,通过setTimeout(),保证在resolve执行之前,then方法已经注册完所有的回调。

2、加入状态

pending :即将发生的状态
fulfilled : 成功状态
rejected : 失败状态

function Promise(fn){
     if(fn && typeof fn !== 'function'){ throw new Error('Promise resolver is not a function') };
	//回调函数数组
this.callBacks = []; //一开始的状态是发生的状态
this.status = 'pending'; //立即执行的参数,初始为null
this._val = Object.create(null); //执行函数
const resolve = val =>{
//改变状态
this.status = 'fulfill'; //立即执行的参数
this._val = val; //执行全部回调
setTimeout(()=>{
this.callBacks.forEach(cb => {
cb(val)
});
})
};
//将resolve作为实参传入fn中并执行,fn的异步什么时候有结果再去执行resolve函数
fn(resolve);
} Promise.prototype.then = function(successCallback){
if (this.status === 'pending') {
this.callBacks.push(successCallback);
}
successCallback(this._val);
}; const promise = new Promise(function(resolve){
//模拟一个异步
setTimeout(()=>{
resolve('我是传给Promise内执行函数的参数')
},2000)
}) promise.then(function(val){
console.log(val);
}); //此时promise实例执行的时候,status已经变为了‘fulfill’,在此之后调用then添加的新回调,都会立即执行。
setTimeout(() => {
promise.then(function(val) {
console.log(val);
});
}, 3000)

  

3、链式

如果在then函数里面再注入一个promise呢?

主要是对then函数和resolve啊含糊的额改造,看这里~

《30分钟,让你彻底明白Promise原理》

4、es6实现写法

class CutePromise {
constructor(executor) {
if (typeof executor !== 'function') {
throw new Error('Executor must be a function');
} this.state = 'PENDING';
this.chained = [];
const resolve = res => {
if (this.state !== 'PENDING') {
return;
} this.state = 'FULFILLED';
this.internalValue = res;
for (const { onFulfilled } of this.chained) {
onFulfilled(res);
}
};
const reject = err => {
if (this.state !== 'PENDING') {
return;
}
this.state = 'REJECTED';
this.internalValue = err;
for (const { onRejected } of this.chained) {
onRejected(err);
}
}; try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
} then(onFulfilled, onRejected) {
if (this.state === 'FULFILLED') {
onFulfilled(this.internalValue);
} else if (this.$state === 'REJECTED') {
onRejected(this.internalValue);
} else {
this.chained.push({ onFulfilled, onRejected });
}
}
} //test
let p = new CutePromise(resolve => {
setTimeout(() => resolve('Hello'), 100);
});
p.then(res => console.log(res));
p = new CutePromise((resolve, reject) => {
setTimeout(() => reject(new Error('woops')), 100);
});
p.then(() => {}, err => console.log('Async error:', err.stack));
p = new CutePromise(() => { throw new Error('woops'); });
p.then(() => {}, err => console.log('Sync error:', err.stack));

  

 

五、总结

1、Promise的构造函数接收一个函数类型的参数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
2、resolve()执行时传入的参数,传到了之后调用的.then()中。
3、reject()执行时传入的参数,传到之后调用的.catch()中。在里面抛出代码函数的异常,不会卡死js.
4、调用getNumber()时候返回Promise的实例对象,这样就 支持了了链式的调用。

  

最新文章

  1. .dtsi .dts dtc dtb 是什么
  2. C语言程序设计第十一次作业
  3. Java中避免表单重复提交
  4. Weblogic页面应用查询oracle数据库后台报错或页面日期格式显示错误
  5. java jstack命令详解
  6. css自定义字体
  7. Docker-创建一个mysql容器,并保存为本地镜像
  8. Mongodb 3.0 创建用户
  9. 由浅入深了解Thrift之客户端连接池化
  10. js打印的两种方法
  11. 201521123093 java 第三周学习总结
  12. 201521123102 《Java程序设计》第9周学习总结
  13. H5 基于Web Storage 的客户端留言板
  14. oracle问题 ORA-01843:not a valid month
  15. 学习Spring必须了解的基础知识——回调机制
  16. Mongo 用户创建及权限管理
  17. AngularJS开发指南14:依赖注入
  18. ACE前摄器Proactor模式
  19. Python 常用内置模块(加密模块 hashlib,Base64)
  20. tony_LVS DR模式 RealServer 为 Windows客户端配置

热门文章

  1. spring MVC中定义异常页面
  2. Apollo单向SSL认证(2)
  3. Spring知识点回顾(04)el 和资源使用
  4. Docker学习笔记 - Docker容器的日志
  5. AOP及专有名词通俗解答
  6. Vue框架axios请求(类似于ajax请求)
  7. Python 爬虫性能相关
  8. pandas(七)数据规整化:清理、转换、合并、重塑之合并数据集
  9. STL迭代器------Traits编程技法详细理解(一)
  10. C语言 时间函数的学习