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 ...
随机推荐
- HTTP协议扫盲(二)HTTP协议的请求方法、请求头和响应头
一.HTTP请求方法 Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST ...
- sass的简介,安装,语法。
一,sass的简介 1,Sass完全兼容所有版本的CSS.我们对此严格把控,所以你可以无缝地使用任何可用的CSS库. 2,Sass已经经过其核心团队超过8年的精心打造. 3,有无数的框架使用Sass构 ...
- JavaScript中Array数组的方法
查找: indexOf.lastIndexOf 迭代:every.filter.forEach.map.somereduce.reduceRight 用法: /* 1 查找方法: * arr.inde ...
- Python之socketserver模块和验证客户端链接的合法性
验证客户端链接的合法性 分布式系统中实现一个简单的客户端链接认证功能 #_*_coding:utf-8_*_ from socket import * import hmac,os secret_ke ...
- 使用Git进行代码版本管理及协同工作
Git简介: git是一种较为先进的代码版本管理及协同工作平台,采用分布式文件块存储: 1. 分布式: 代码保存在所有协同成员的计算机上,网速较差时依然可用:而传统的集中式代码版本管理系统则较难脱离 ...
- 错误解决:HibernateSystemException-HHH000142: Javassist Enhancement failed
今天做项目报了一个错误 错误的原因是: 有级联查询的时候,一对多,多对一配置时要考虑默认延迟加载的问题,需要把延迟加载关闭. 然后就能正确查询出结果了 补充知识: 延迟加载表现在:比如:我们要查询 ...
- python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- CWMP开源代码研究——cwmp移植
原创作品,转载请注明出处,严禁非法转载.如有错误,请留言! email:40879506@qq.com 声明:本系列涉及的开源程序代码学习和研究,严禁用于商业目的. 如有任何问题,欢迎和我交流.(企鹅 ...
- Text-鼠标点击事件
from tkinter import * import webbrowser master=Tk() text=Text(master,width=50,height=20) text.pack() ...
- Javascript中的url编码与解码(详解)
摘要 本文主要针对URI编解码的相关问题做了介绍,对url编码中哪些字符需要编码.为什么需要编码做了详细的说明,并对比分析了Javascript中和编解码相关的几对函数escape / unescap ...