博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
看完这篇,Promise面试就搞定了...
阅读量:6076 次
发布时间:2019-06-20

本文共 7341 字,大约阅读时间需要 24 分钟。

1.Promise

Promise是目前比较流行的异步解决方案,本质上一个构造函数。

1.1状态

promise有三种状态,初始状态是pedding,包括:

  • 成功状态 pedding => resolve
  • 失败状态 pedding => reject
  • 等待状态 pedding

我们先来看一个简单的例子

let promise = new Promise(function(resolve,reject){    //throw new Error('出错了')    //resolve()    reject()});promise.then(()=>{    console.log('success')},()=>{    console.log('error');});复制代码

每个promise的实例都有then方法,包额括两个参数,分别是成功的回调会失败的回调,同时支持多次then,成功就回调所有成功方法失败也是如此,本质上then是一个异步的,也称为微任务。 其他方法还包括:

  • Promise.all() 所有的promise对象成功才会触发成功状态,否则失败状态
  • Promise.race() 任意一个子pormise的状态触发后会被父promise立即调用,完成一个即可

2. 自己实现一个Promise

所有的promise都要遵循promiseA+规范

2.1简易版

function Promise(executor){     let self = this;    self.value = undefined; //定义成功的value    self.reason = undefined; //定义失败的reson    self.status = 'pending'; //初始化状态为pedding    function resolve(value){        if(self.status === 'pending'){ //只有pedding的时候状态才可以改变            self.value = value;            self.status = 'resolved';        }    }    function reject(reason){        if(self.status === 'pending'){ //只有pedding的时候状态才可以改变            self.reason = reason;            self.status = 'rejected';        }    }    // 如果函数执行时发生异常throw new Error,就失败    try{        executor(resolve,reject); //executor 默认new的时候就自动执行    }catch(e){        reject(e);    }}Promise.prototype.then = function(onFulfilled,onRejected){    let self = this;    //判断当前状态    // 成功状态时    if(self.status === 'resolved'){//如果成功,执行成功,并把成功原因传过去        onFulfilled(self.value);//上面的实例then中成功回调(console.log('success'))    }    // 失败状态时    if(self.status === 'rejected'){//如果失败,执行失败,并把失败原因传过去        onRejected(self.reason);//上面的实例then中失败回调(console.log('error'))    }}module.exports = Promise;复制代码

2.2 稍微完善

但当在new Promise 中加入有异步方法,如下3秒后才开始执行成功,此时resolve会延迟执行,then中的状态又不是成功,又不是失败,因此会不执行成功或者失败方法,因为需要将成功或者失败的方法用数组存起来

let promise = new Promise(function(resolve,reject){    setTimeout(()=>{        resolve()    },3000)});复制代码

来完善的例子

function Promise(executor){    let self = this;    self.value = undefined;    self.reason = undefined;    self.status = 'pending';    self.onResolvedCallbacks = [];// 存放then中成功的回调    self.onRejectedCallbacks = []; // 存放then中失败的回调    function resolve(value){        if(self.status === 'pending'){            self.value = value;            self.status = 'resolved';            self.onResolvedCallbacks.forEach(fn=>fn());//循环执行成功        }    }    function reject(reason){        if(self.status === 'pending'){            self.reason = reason;            self.status = 'rejected';            self.onRejectedCallbacks.forEach(fn=>fn());//循环执行失败        }    }    try{        executor(resolve,reject);    }catch(e){        reject(e);    }}// onFulfilled成功的回调 onRejected失败的回调Promise.prototype.then = function(onFulfilled,onRejected){    let self = this;    if(self.status === 'resolved'){        onFulfilled(self.value);    }    if(self.status === 'rejected'){        onRejected(self.reason);    }    if(self.status === 'pending'){//当等待状态时候,保存回调函数        self.onResolvedCallbacks.push(()=>{            onFulfilled(self.value);        });        self.onRejectedCallbacks.push(()=>{            onRejected(self.reason)        });    }}module.exports = Promise;复制代码

2.3 链式调用

我们知道Promise可以一直then下去,来实现链式调用,但上面的例子明显不可以实现 例如

let p = new Promise((resolve,reject) =>{    resolve(123)})let p1 = new Promise((resolve,reject) =>{    resolve(111)})p.then((data)=>{    console.log(data)    return p1 //返回的p1是一个新的promise,继续成功下去,把111传给下一个newData,失败也是如此,如果返回的是普通值,直接把值作为下一层then的参数,所以需要判断p1是不是promise}).then((newData)=>{    console.log('p1',data)})复制代码

完善代码

function Promise(executor) {    let self = this;    self.value = undefined;     self.reason = undefined;     self.status = 'pending';     self.onResolvedCallbacks = [];      self.onRejectedCallbacks = [];    function resolve(value) {         if (self.status === 'pending') {            self.value = value;            self.status = 'resolved';            self.onResolvedCallbacks.forEach(fn => fn());        }    }    function reject(reason) {         if (self.status === 'pending') {            self.reason = reason;            self.status = 'rejected';            self.onRejectedCallbacks.forEach(fn => fn());        }    }    try {        executor(resolve, reject);    } catch (e) {        reject(e);    }}/** *  * @param {*} promise2  then的返回值 (返回的新的promise) * @param {*} x  then中成功或者失败函数的返回值 * @param {*} resolve promise2的resolve * @param {*} reject  promise2的reject */function resolvePromise(promise2,x,resolve,reject){    // promise2和函数执行后返回的结果是同一个对象,自己等待自己执行,不可以    
if(promise2 === x){ return reject(new TypeError('Chaining cycle')); } let called; // x可能是一个promise 或者是一个普通值 if(x!==null && (typeof x=== 'object' || typeof x === 'function')){ try{ let then = x.then; // 这个promise可能是别人乱写的,所以try catch // x可能还是一个promise 那么就让这个promise执行即可 if(typeof then === 'function'){ then.call(x,y=>{ // 返回promise后的成功结果 // 递归直到解析成普通值为止 if(called) return; // 防止多次调用 called = true; // 递归 可能成功后的结果是一个promise 那就要循环的去解析 resolvePromise(promise2,y,resolve,reject); },err=>{ // promise的失败结果 if(called) return; called = true; reject(err); }); }else{ resolve(x); } }catch(e){ if(called) return; called = true; reject(e); } }else{ // 如果x是一个常量 resolve(x); }}Promise.prototype.then = function (onFulfilled, onRejected) { let self = this; let promise2; // 需要每次调用then时都返回一个新的promise promise2 = new Promise((resolve, reject) => {//相当于调完了then又返回了一个promise if (self.status === 'resolved') { setTimeout(()=>{ try { // 当执行成功回调的时候可能会出现异常,那就用这个异常作为promise2的错误的结果 let x = onFulfilled(self.value); //新的promise,也就是then的返回结果 //执行完当前成功回调后返回结果可能是promise resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); } },0) } // 规范要求加setTimeout if (self.status === 'rejected') { setTimeout(()=>{ try { let x = onRejected(self.reason); resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); } },0) } if (self.status === 'pending') {//等待的时候也要包装一个promise2 self.onResolvedCallbacks.push(() => { setTimeout(()=>{ try { let x = onFulfilled(self.value); resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); } },0) }); self.onRejectedCallbacks.push(() => { setTimeout(()=>{ try { let x = onRejected(self.reason); resolvePromise(promise2,x,resolve,reject); } catch (e) { reject(e); } },0) }); } }); return promise2}module.exports = Promise;复制代码

转载地址:http://fuagx.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
用yum安装mariadb
查看>>
一点IT"边缘化"的人的思考
查看>>
Gallery循环滑动
查看>>
Sql与C#中日期格式转换总结
查看>>
iOS开发流程总结
查看>>
hadoop datanode 启动出错
查看>>
js颜色拾取器
查看>>
IDEA使用(1)intellIJ idea 配置 svn
查看>>
WPF 降低.net framework到4.0
查看>>
数据管理DMS 全量SQL诊断:你的SQL是健康的蓝色,还是危险的红色?
查看>>
搭建一个通用的脚手架
查看>>
开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
查看>>
开源磁盘加密软件VeraCrypt教程
查看>>
本地vs云:大数据厮杀的最终幸存者会是谁?
查看>>
阿里云公共镜像、自定义镜像、共享镜像和镜像市场的区别 ...
查看>>
shadowtunnel v1.7 发布:新增上级负载均衡支持独立密码
查看>>
Java线程:什么是线程
查看>>
mysql5.7 创建一个超级管理员
查看>>
【框架整合】Maven-SpringMVC3.X+Spring3.X+MyBatis3-日志、JSON解析、表关联查询等均已配置好...
查看>>