promise是用来解决Js中的异步问题的,js中所有的异步可从callback → promise → generator + co = async + await

其实所有的都是callback的变相处理,只是后者慢慢变的越来越优雅和强壮可扩展。

那么如何实现promise呢?先观察一下promise的样子

let  a = new Promise((resolve,reject)=>{
// dosomething
resolve()
})

无非是一个名称叫Promise的对象,然后传参一个函数 (resolve,reject)=>{resolve()}

promise的强大之处在于回调处理,promise.then(resolveFunticon,rejectFunction)

第一个函数是resolve的回调处理函数,第二个是reject

说到resovle,reject,那么还得再提一下pending,promise对象内部有以上三种状态。默认是pending状态

状态的转变需要我们手动自己去调用函数resolve()或者reject()

整理一下思路:new promise的时候callback作为传参参数执行promise函数,callback在promise函数内部执行。callback里手动调用的resolve或者reject方法,那么promise对象里肯定是有这两种方法的。

最关键的是记住状态,然后再then的时候根据状态去判断到底是执行resolveFunticon还是rejectFunction。

function PromiseFn(callBack){
let self = this;
self.resolveVal = undefined;
self.rejectVal = undefined;
self.status = 'pending'//默认是等待状态 function resolve(val){
if(self.status === 'pending'){
self.resolveVal = val;
self.status = 'resolve'
}
}
function reject(val){
if(self.status === 'pending'){
self.rejectVal = val;
self.status = 'reject'
}
}
     //这里要注意,try catch若是写在 let self = this 会报错,let存在暂时死区,没有常规的变量提升。必须先申明后使用
     // callback执行,调用resolve函数。
try{
callBack(resolve,reject)//callback进来自动执行
}catch(e){
reject()//若是有报错,则直接变为reject状态
}
}

上面关于let的深入可以去看这篇博客:我用了两个月的时候才理解let

可能会被callback给弄得有点懵,其实把它当做函数fn就行,fn在promise内部执行,然后fn内部刚好有个resolve(),然后再去调用promise的这个resolve执行。

也就是这个原因,所以callback的参数必须是resolve和reject。

上面这一步,需要注意的是callback是立即执行的。下面这段会立即打印111

let  a = new Promise((resolve,reject)=>{
console.log('111')
})
console.log('456')

上面我们定义了 resolveVal 和 rejectVal,因为待会在promise调用then执行的时候,会作为参数传参给resolveFunticon或者rejectFunction

所以promise对象内部必须记住这个参数。

下面一起看看promise.then吧,promise.then(resolveFunticon,rejectFunction)。在promise的原型链上有个then方法

PromiseFn.prototype.then = function(resolveFunction,rejectFunction){
  let self = this;
  if(self.status === 'resolve'){
resolveFunction(self.resolveVal)
  }
  if(self.status === 'reject'){
rejectFunction(self.rejectVal)
  }
}

在then执行的时候,去判断内部是啥状态,然后执行对应的resolve或者reject回调函数。  

然后运行试一试

let promiseA = new PromiseFn((resolve,reject)=>{
resolve('成功啦')
})
promiseA.then((resolveVal)=>{
console.log('resolve'+resolveVal)
},(rejectVal)=>{
console.log('reject'+rejectVal)
})

结果是:  

但是这样就结束了吗?no,我们一般对Promise的使用场景可能是下面这样的,需要考虑异步问题。

let promiseA = new PromiseFn((resolve,reject)=>{
setTimeout(function(){
resolve('成功啦')
},2000)
})

这里用settimeout代替一下,一般我们都是一个ajax请求,然后在请求到结果后去resolve.

上面的写法显然是无法满足这种条件的,当去执行promise.then的时候,发现状态还是pending,不做任何执行。

那我们怎么去做呢?发现状态是pending,肯定是两秒钟之内啦,不妨先把promise.then两个函数参数先在promise里面记下来,两秒钟后状态变为resolve了,再执行函数。

      function PromiseFn(callBack){
try{
callBack(resolve,reject)
}catch(e){
reject()
}
let self = this;
self.resolveVal = undefined;
self.rejectVal = undefined;
self.status = 'pending'//默认是等待状态
self.keepResolveFn = []//
self.keepRejectFn = []// function resolve(val){
if(self.status === 'pending'){
self.resolveVal = val;
self.status = 'resolve';
self.keepResolveFn.forEach(fn=>fn());
}
}
function reject(val){
if(self.status === 'pending'){
self.rejectVal = val;
self.status = 'reject';
self.keepRejectFn.forEach(fn=>fn());
}
}
//执行先记录resolve和reject函数事件 }
PromiseFn.prototype.then = function(resolveFunction,rejectFunction){
let self = this;
if(self.status === 'resolve'){
resolveFunction(self.resolveVal)
}
if(self.status === 'reject'){
rejectFunction(self.rejectVal)
}
if(self.status === 'pending'){
self.keepResolveFn.push(()=>{
resolveFunction(self.resolveVal);
});
self.keepRejectFn.push(()=>{
rejectFunction(self.rejectVal)
});
}
}
let promiseA = new PromiseFn((resolve,reject)=>{
setTimeout(function(){
resolve('成功啦')
},2000)
})
promiseA.then((resolveVal)=>{
console.log('resolve'+resolveVal)
},(rejectVal)=>{
console.log('reject'+rejectVal)
})

结果是:延迟两秒后,打印出  ‘resolve成功啦’。

最后多提一句:所有的then方法执行,也是通过return 一个新的promise对象来执行的。这样才有链式回调,new promise.then().then().then()

        var b = 10;
new Promise((resolve, reject) => { setTimeout(() => {
b += 10;
resolve();
// reject();
}, 1000); }).then(function() {
console.log(b);
return new Promise((resolve, reject) => {
setTimeout(() => {
b *= 2;
resolve();
}, 1000);
});
}).then(function() {
console.log(b);
return new Promise((resolve, reject) => {
setTimeout(() => {
b *= b;
resolve();
}, 1000);
});
}).then(function() {
console.log(b);
},function() {
console.log('失败了');
});

  

  

 

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

  1. Promise原理 && 简单实现

    Promise原理 参考https://github.com/chunpu/promise/blob/master/promise.js 个人认为原博的实现有点问题 在next函数的实现上, 会导致无 ...

  2. Promise 原理

    异步:可同时好几件事,互不影响: 同步:按循序一件一件.... 异步好多缺点:.... promise就是解决异步计算的这些缺点的,主要用于: 1.异步计算: 2.可以将异步操作队列化  按期望的顺序 ...

  3. Sea.Js的运行原理(转)

    1.CMD(Common Module Definition)规范 Sea.js采用了和Node相似的CMD规范,使用require.exports和module来组织模块.但Sea.js比起Node ...

  4. 深入研究Node.js的底层原理和高级使用

    深入研究Node.js的底层原理和高级使用

  5. promise原理

      简介 Promise 对象用于延迟(deferred) 计算和异步(asynchronous )计算.一个Promise对象代表着一个还未完成,但预期将来会完成的操作.Promise 对象是一个返 ...

  6. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

  7. vue.js响应式原理解析与实现

    vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...

  8. 深入解析vue.js响应式原理与实现

    vue.js响应式原理解析与实现.angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很好奇vue.js是如何监测数据更新并且重新渲染页面.vue.js ...

  9. 浅谈Generator和Promise原理及实现

    Generator 熟悉ES6语法的同学们肯定对Generator(生成器)函数不陌生,这是一个化异步为同步的利器. 栗子: function* abc() { let count = 0; whil ...

随机推荐

  1. (转)shell中各种括号的作用()、(())、[]、[[]]、{}

    shell中各种括号的作用().(()).[].[[]].{} 原文:http://www.jb51.net/article/60326.htm http://blog.csdn.net/good_h ...

  2. LeetCode 887.鸡蛋掉落(C++)

    每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去. 你知道存在楼层 F ,满足 0 <= F <= N 任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的 ...

  3. java语言编程实现两个时间相差多少天、多少小时、多少分、多少秒

    不多说,直接上干货! DateDistance.java package zhouls.bigdata.DataFeatureSelection.test; import java.text.Date ...

  4. haproxy简单配制for mysql

    1:下载haproxy 官网:http://www.haproxy.org/ 下载地址:http://www.haproxy.org/download/1.7/src/haproxy-1.7.8.ta ...

  5. 连接虚机中的mysql服务

    1:修改mysql库中的user表的root用户的host值为% 2:授权:在mysql命令中执行 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFI ...

  6. 使用CSS选择器进行元素定位

    在selenium webdriver中,支持使用CSS选择器来进行元素定位,事实在真的投入工作,大量编辑用例和元素定位的时候,使用css 和 xpath才是经常需要用到的. 之前有专门讲过使用xpa ...

  7. linux 下库的深入调研

    linux操作系统中,linux库文件路径还是比较常用的,于是我研究了一下linux库文件路径,在这里拿出来和大家分享一下,希望对大家有用. 库文件在连接(静态库和共享库)和运行(仅限于使用共享库的程 ...

  8. plupload2.1.2文件合并

    1.前端 (1)依赖文件: <link type="text/css" rel="stylesheet" href="~/Content/plu ...

  9. Ajax Jq Razor语句

    1.JS刷新当前页面: window.location.reload(); 2.JSon成功后转向其他页面: window.location.href="要转向页面的地址(一般格式:/页面所 ...

  10. MongoDB之mongodb.cnf配置

    # mongodb3.2.1 的主配置文件,将此文件放置于 mongodb3.2.1/bin 目录下 # hapday 2016-01-27-16:55 start # 数据文件存放目录 dbpath ...