promise应用及原生实现promise模型
一、先看一个应用场景
发送一个请求获得用户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啊含糊的额改造,看这里~
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的实例对象,这样就 支持了了链式的调用。
promise应用及原生实现promise模型的更多相关文章
- 原生的 promise 的局限性
本文来自:https://ekyu.moe/article/limits-of-native-promise-and-async-await/ 众所周知,Nodejs 已原生支持 Promise 和 ...
- 【es6】js原生的promise
JavaScript 是单线程的,这意味着任何两句代码都不能同时运行,它们得一个接一个来.在浏览器中,JavaScript 和其他任务共享一个线程,不同的浏览器略有差异,但大体上这些和 JavaScr ...
- 大白话讲解Promise(二)理解Promise规范
上一篇我们讲解了ES6中Promise的用法,但是知道了用法还远远不够,作为一名专业的前端工程师,还必须通晓原理.所以,为了补全我们关于Promise的知识树,有必要理解Promise/A+规范,理解 ...
- Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)
1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...
- promise详解 : 实现promise(附实现代码)
promise then 的特点 : then 函数的返回值是一个 promise, 可以继续调用 then 函数 回调函数 resolve 和 reject 的参数 value /reason, 可 ...
- Promise.resolve()与Promise
//Promise.resolve()和Promise.reject()常用来生成已经被决议为失败或者成功的promise案例 //Promise.reject()简单一些,不管传给它什么值,它决议为 ...
- 关于ES6中Promise的应用-顺序合并Promise,并将返回结果以数组的形式输出
1.Promise 基础知识梳理 创建一个Promise实例 const promise = new Promise(function(resolve, reject) { if (success){ ...
- 原生Ajax + Promise
有原生写的ajax + promise嫁接下 ;(function(root){ var LD = function(obj){ if( obj instanceof LD ) return obj; ...
- js原生方法promise的实现
一会儿就要回家过年了,再来手写一个promise吧,要不等着下班真的煎熬... <!DOCTYPE html> <html lang="en"> <h ...
随机推荐
- SpringCloud的服务注册中心(一)
一.概念和定义 1.服务治理:服务注册与服务发现 服务注册中心,提供服务治理功能,用来实现各个微服务实例的自动注册与发现. 服务注册与发现对于微服务系统来说非常重要.有了服务发现与注册,维护人员就不需 ...
- nodejs调试总结
之前nodejs开发中最痛苦的就是调试,因为我之前开发node时使用的编辑器还没有将nodejs的调试也集成进去,所以简单对nodejs开发的调试做了点探索,nodejs本身就有调试功能,同时node ...
- django中图片的上传和显示
上传图片实际上是 把图片存在服务器的硬盘中,将图片存储的路径存在数据库中. 1 首先要配置文件上传的路径: 1.1 建立静态文件目录 在项目根目录下 新建一个 static文件夹,下面再建立一个med ...
- python--socket/Socketerver并发/udp
Socketerve并发 基于tcp套接字,关键就是两个循环,一个链接循环,一个通讯循环 Socketserver模块中分两个大类:server类(解决链接问题)和request类(解决通信问题) s ...
- CMDB开发
浅谈ITIL TIL即IT基础架构库(Information Technology Infrastructure Library, ITIL,信息技术基础架构库)由英国政府部门CCTA(Central ...
- Oracle12c:支持通过创建identity columen来实现创建自增列
oracle12c之前如果需要创建自增列必须要通过sequence+trigger来实现.但是oracle12c已经可以像mysql,sqlserver一样通过identity column来设置自增 ...
- 【Python3.6+Django2.0+Xadmin2.0系列教程一】环境搭建及项目创建
由于工作需要,接触了大半年时间的Django+xadmin框架,一直没空对这块对进行相关的梳理.最近在同事的怂恿下,就在这分享下笔者的学习及工作经验吧. 好了,话不多说,下面开始进入正题: 环境需求: ...
- requests之一:HTTP OAUTH认证(1)图形解释流程
- 初探java对象比较
判断两个对象的属性值是否相等的方法, class Book{ private String title; private double price; public Book(String title, ...
- [JSOI2008]Blue Mary开公司
Description Input 第一行 :一个整数N ,表示方案和询问的总数. 接下来N行,每行开头一个单词“Query”或“Project”. 若单词为Query,则后接一个整数T,表示Bl ...