长篇预警!有点长,可以选择性观看。如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的。主要是代码部分有点多,不过好多都是重复的,不必担心
Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难
先大概说一下基本概念:
Promise内部维护着三种状态,即pending,resolved和rejected。初始状态是pending,状态可以有pending--->relolved,或者pending--->rejected.不能从resolve转换为rejected 或者从rejected转换成resolved.
即 只要Promise由pending状态转换为其他状态后,状态就不可变更。
ok.知道了这些后,我们开始手撸代码:
注意观看序号 1 2 3 4 5 ...
function Promise(executor){
let that = this;
/** 2 定义初始的一些变量 */
that.status = 'pending';
that.value = null;
that.reason = null;
/** 3 定义初始的成功和失败函数 */
function resolve(value){
/** 4 判断状态是不是初始状态pending
* 是就转换状态 否则不转换
* 确保状态的变化后的不可变性 */
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
}
}
function reject(reason){
/** 5 同上 */
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
}
}
/**
* 1 Promise中首先传了一个executor,它是一个函数
* executor函数中又传了两个函数,分别是resolve和reject
* 很显然 resolve是成功回调,reject是失败的回调
*/
executor(resolve,reject);
}
/** 6 在Promise原型上面定义then方法
* then方法上面有两个回调 一个是成功后的方法 另一个是失败后的方法
* 根据成功或失败的状态去执行相关成功onFilfulled()或者失败onRejected()的回调方法
*/
Promise.prototype.then = function(onFilfulled,onRejected){
let that = this;
if(that.status === 'resolved'){
/** 7 如果状态已经变更为resolved
* 说明resolve方法已经被调用
* 那么此时就执行成功的回调函数onFilfulled
* 并传入参数 that.value
* */
onFilfulled(that.value);
}
if(that.status === 'rejected'){
/** 8 同上
* 传入参数 that.reason
*/
onRejected(that.reason);
}
}
module.exports = Promise;
通过require()引入手撸的Promise
let Promise = require('./myPromise');
let p1 = ()=>{
return new Promise((resolve,reject)=>{
resolve('success.1');
});
}
p1().then((data)=>{
console.log(data); // 打印 success.1
},(err)=>{
console.log(err);
});
ok.经调用发现 此代码可以实现部分Promise的功能,但仅仅是同步下才有效果。
那异步呢? 别急这就来~:
注意观看序号 1 2 3 4 5 ...
function Promise(executor){
let that = this;
that.status = 'pending';
that.value = null;
that.reason = null;
/** 1 因为异步不是立即执行 状态不会变更 成功或失败的回调函数也不会执行
* 所以先定义好存放成功或失败回调函数的数组
* 以便将成功或失败的回调函数先保存起来
* */
that.onFilFulledCallbacks = [];
that.onRejectedCallbacks = [];
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
/** 3 发布
* 等待状态发生变更
* 状态变更后 立即执行之前存放在相应数组中所有的成功或失败的回调函数
* 即 发布
*/
that.onFilFulledCallbacks.forEach((fn)=>{
fn();
});
}
}
function reject(reason){
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
/** 4 同上 */
that.onRejectedCallbacks.forEach((fn)=>{
fn();
});
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFilfulled,onRejected){
let that = this;
if(that.status === 'resolved'){
onFilfulled(that.value);
}
if(that.status === 'rejected'){
onRejected(that.reason);
}
/** 2 订阅
* 因为是异步 状态当时并没有立即变更 所以状态还是pending
* 此时需要把成功或者失败的回调函数存放到对应的数组中
* 等待状态变更时 再从数组中拿出来去执行
* 即 订阅
* *存放数组时 为了执行时方便 需要把回调函数的外层包裹一层空函数
*/
if(that.status === 'pending'){
that.onFilFulledCallbacks.push(function(){
onFilfulled(that.value);
});
}
if(that.status === 'pending'){
that.onRejectedCallbacks.push(function(){
onRejected(that.reason);
});
}
}
module.exports = Promise;
代码测试:
let Promise = require('./myPromise');
let p1 = ()=>{
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('success.1');
// reject('fail.');
},1500);
});
}
p1().then((data)=>{
console.log(data); // success.1
},(err)=>{
console.log(err);
});
可以看到 1.5s后 执行了resolve() 并打印了success.1,至此,我们实现了异步的Promise.其实这里的实现异步的思想就是发布订阅.
en~ok.接下来就稍稍复杂了 因为我们要实现链式调用then。 要实现这个功能那我们就要重写then方法,并在then方法中重新返回一个Promise,只有这样,才可以实现多次调用then.而且要新增一个解析返回值是否为promise的函数.
稍微捋下逻辑:
上代码:
注意观看序号 1 2 3 4 5 ...
function Promise(executor){
let that = this;
that.status = 'pending';
that.value = null;
that.reason = null;
that.onFilFulledCallbacks = [];
that.onRejectedCallbacks = [];
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
that.onFilFulledCallbacks.forEach((fn)=>{
fn();
});
}
}
function reject(reason){
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
that.onRejectedCallbacks.forEach((fn)=>{
fn();
});
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFilfulled,onRejected){
let that = this;
/** 1 让promise2等于一个新的Promise 并将promise2返回 */
let promise2 = new Promise((resolve,reject)=>{
if(that.status === 'resolved'){
/** 2 因为返回了promise2
* 并且第3步resolvePromiseRelation函数中传递了promise2
* 而目前promise2并没有拿到
* 所以加一个定时器 异步执行 等到promise2拿到后
* 再去执行 resolvePromiseRelation()方法 并将promise2传递进去*/
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
/** 3 判断新返回值是什么类型的函数
* 并将当前的promise:promise2 新的返回值:promise3
* 和 成功时回调:esolve 失败时回调:reject 作为参数传进去 */
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'rejected'){
/** 同2 */
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
/** 同3*/
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'pending'){
that.onFilFulledCallbacks.push(function(){
/** 同2 */
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
/** 同3*/
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
if(that.status === 'pending'){
that.onRejectedCallbacks.push(function(){
/** 同2 */
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
/** 同3*/
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
});
/** 同1 */
return promise2;
}
function resolvePromiseRelation(promise2,promise3,resolve,reject){
/** 4 防止自己等待自己 一直循环等待 */
if(promise2 === promise3){
return reject(new TypeError('循环引用了!'));
}
/** 8 一个标示 表示当前没有被调用过
* 确保resolve或者reject后的状态不会再次发生变更
*/
let called;
/** 5 保证promise3是一个引用类型
* 判断新返回值promise3的类型
* 如果是普通值常量 就直接resolve导出 */
if(promise3!==null&&(typeof promise3 === 'object'||typeof promise3 === 'function')){
try{
let then = promise3.then;
/** 6 确保promise3是一个Promise
* 判断promise3的then方法
* 如果存在 并且是一个function类型
* 就表示promise3是一个Promise */
if(typeof then === 'function'){
/** 9 执行promise3的then方法
* 因为promise3也是一个Promise
* 需要再次解析promise3的then方法
* 直到解析到最后的返回值不是一个Promise类型为止
*/
then(promise3, (promise4)=>{
/** 同8 */
if(called) return;
called = true;
/** 10 递归解析新的返回值的类型
* 解析到返回值不是一个Promise类型为止
*/
resolvePromiseRelation(promise3,promise4,resolve,reject);
},(r)=>{
/** 同8 */
if(called) return;
called = true;
reject(r);
});
}else{
/** 7 此时promise3是一个普通对象 直接resolve() */
resolve(promise3);
}
}catch(e){
/** 同8 */
if(called) return;
called = true;
reject(e);
};
}else{
/** 同5 普通值直接resolve()*/
resolve(promise3);
}
}
module.exports = Promise;
ok. 至此 我们已经实现了Promsie的异步和链式调用. Promise中比较复杂的部分我们已经搞定了 接下来就是添加一些方法,其实这部分反而没那么复杂了.
catch : catch方法本质上就是一个then方法的变形,只有失败时的回调 没有成功时的回调
finally : finally方法的作用是不管 Promise 对象最后状态如何,都会执行操作.其实说白了就是在then方法的成功和失败的回调函数中都执行该方法就行了.
ok.老规矩 上代码~
function Promise(executor){
let that = this;
that.status = 'pending';
that.value = null;
that.reason = null;
that.onFilFulledCallbacks = [];
that.onRejectedCallbacks = [];
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
that.onFilFulledCallbacks.forEach((fn)=>{
fn();
});
}
}
function reject(reason){
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
that.onRejectedCallbacks.forEach((fn)=>{
fn();
});
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFilfulled,onRejected){
/** 2 此处有个坑 如果只写1 不写2的话
* 会报一个TypeError :onRejected is not a function
* 在此处给它一个默认的成功和失败的回调函数就好 */
onFilfulled = typeof onFilfulled === 'function'?onFilfulled:value=>value;
onRejected = typeof onRejected === 'function'?onRejected:err=>{throw err};
let that = this;
let promise2 = new Promise((resolve,reject)=>{
if(that.status === 'resolved'){
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'rejected'){
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'pending'){
that.onFilFulledCallbacks.push(function(){
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
if(that.status === 'pending'){
that.onRejectedCallbacks.push(function(){
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
});
return promise2;
}
function resolvePromiseRelation(promise2,promise3,resolve,reject){
if(promise2 === promise3){
return reject(new TypeError('循环引用了!'));
}
let called;
if(promise3!==null&&(typeof promise3 === 'object'||typeof promise3 === 'function')){
try{
let then = promise3.then;
if(typeof then === 'function'){
then(promise3, (promise4)=>{
if(called) return;
called = true;
resolvePromiseRelation(promise3,promise4,resolve,reject);
},(r)=>{
if(called) return;
called = true;
reject(r);
});
}else{
resolve(promise3);
}
}catch(e){
if(called) return;
called = true;
reject(e);
};
}else{
resolve(promise3);
}
}
/** 1 直接返回this的then方法
* 因为catch只捕获错误 所以resolve直接为null
* 返回reject就好*/
Promise.prototype.catch = function(errFn){
return this.then(null,errFn);
}
/** 3 finally实现起来也很简单
* 分别在resolve和reject中执行fn就好
* 最后再把this返回出去就好
*/
Promise.prototype.finally = function(fn){
this.then(()=>{
fn();
},()=>{
fn();
});
return this;
}
module.exports = Promise;
function Promise(executor){
let that = this;
that.status = 'pending';
that.value = null;
that.reason = null;
that.onFilFulledCallbacks = [];
that.onRejectedCallbacks = [];
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
that.onFilFulledCallbacks.forEach((fn)=>{
fn();
});
}
}
function reject(reason){
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
that.onRejectedCallbacks.forEach((fn)=>{
fn();
});
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFilfulled,onRejected){
onFilfulled = typeof onFilfulled === 'function'?onFilfulled:value=>value;
onRejected = typeof onRejected === 'function'?onRejected:err=>{throw err};
let that = this;
let promise2 = new Promise((resolve,reject)=>{
if(that.status === 'resolved'){
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'rejected'){
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'pending'){
that.onFilFulledCallbacks.push(function(){
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
if(that.status === 'pending'){
that.onRejectedCallbacks.push(function(){
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
});
return promise2;
}
function resolvePromiseRelation(promise2,promise3,resolve,reject){
if(promise2 === promise3){
return reject(new TypeError('循环引用了!'));
}
let called;
if(promise3!==null&&(typeof promise3 === 'object'||typeof promise3 === 'function')){
try{
let then = promise3.then;
if(typeof then === 'function'){
then(promise3, (promise4)=>{
if(called) return;
called = true;
resolvePromiseRelation(promise3,promise4,resolve,reject);
},(r)=>{
if(called) return;
called = true;
reject(r);
});
}else{
resolve(promise3);
}
}catch(e){
if(called) return;
called = true;
reject(e);
};
}else{
resolve(promise3);
}
}
Promise.prototype.catch = function(errFn){
return this.then(null,errFn);
}
Promise.prototype.finally = function(fn){
this.then(()=>{
fn();
},()=>{
fn();
});
return this;
}
/** 1 直接在构造函数上增加all方法
* 它返回的也是一个Promise
* 等待参数数组中所有的promise都执行完毕后
* 再返回结果
*/
Promise.all = function(values){
return new Promise((resolve,reject)=>{
/** 2 定义一个存放最终结果的数组result和一个index */
let results = [];
let index = 0;
/** 3 定义一个方法addToArr()
* 让index每次执行增加results数组元素的函数的时候都+1
* 当index === values的长度的时候 说明此时所有promsie都执行完毕并放到的数组中
* 然后直接resolve(results)就行了
*/
function addToArr(key,value){
index++;
results[key] = value;
/** 6 当满足条件时 说明所有的promise都执行完毕 直接resolve(results) */
if(index === values.length){
resolve(results);
}
}
/** 4 循环values中的每一项promsie */
for(let i = 0; i < values.length; i++){
let current = values[i];
/** 5 判断每一项promise的返回值是不是一个Promsie
* 是的话就执行该Promise的then方法 拿到返回值 并放到数组results中
* 是一个普通值的话就直接将该值放到数组results中
*/
if(current && current.then && typeof current.then === 'function'){
current.then((value)=>{
/** 同5 把返回值放到数组results中*/
addToArr(i,value);
},reject);
}else{
/** 同5 把返回值放到数组results中*/
addToArr(i,current);
}
}
});
}
/** race方法相比较于all方法简单很多
* 因为race中的promsie成功resolve一个
* 整个race就resolve */
Promise.race = function(values){
return new Promise((resolve,reject)=>{
/** 同4 */
for(let i = 0; i < values.length; i++){
let current = values[i];
/** 同5 */
if(current&¤t.then&&typeof current.then === 'function'){
/** 7 直接执行then就好 */
current.then(resolve,reject);
}else{
/** 8 普通值直接resolve */
resolve(current);
}
}
});
}
// resolve方法
Promise.resolve = function(value){
return new Promise((resolve,reject)=>{
resolve(value);
});
}
// reject方法
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
reject(reason);
});
}
module.exports = Promise;
此步是为了测试我们手写的Promsie符不符合Promsie/A+规范,如果没有defer的话,我们在测试过程中就会报一个TypeError: adapter.deferred is not a function.
其实写完defer后,我们就可以去进行测试我们手写的Promsie符不符合Promsie/A+规范了。
即:本篇手写一款符合Promise/A+规范的Promise的最终本为:
function Promise(executor){
let that = this;
that.status = 'pending';
that.value = null;
that.reason = null;
that.onFilFulledCallbacks = [];
that.onRejectedCallbacks = [];
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
that.onFilFulledCallbacks.forEach((fn)=>{
fn();
});
}
}
function reject(reason){
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
that.onRejectedCallbacks.forEach((fn)=>{
fn();
});
}
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
Promise.prototype.then = function(onFilfulled,onRejected){
onFilfulled = typeof onFilfulled === 'function'?onFilfulled:value=>value;
onRejected = typeof onRejected === 'function'?onRejected:err=>{throw err};
let that = this;
let promise2 = new Promise((resolve,reject)=>{
if(that.status === 'resolved'){
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'rejected'){
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
}
if(that.status === 'pending'){
that.onFilFulledCallbacks.push(function(){
setTimeout(()=>{
try{
let promise3 = onFilfulled(that.value);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
that.onRejectedCallbacks.push(function(){
setTimeout(()=>{
try{
let promise3 = onRejected(that.reason);
resolvePromiseRelation(promise2,promise3,resolve,reject);
}catch(e){
reject(e);
}
},0);
});
}
});
return promise2;
}
function resolvePromiseRelation(promise2,promise3,resolve,reject){
if(promise2 == promise3){
return reject(new TypeError('循环引用了!'));
}
let called;
if(promise3!==null&&(typeof promise3 === 'object' || typeof promise3 === 'function')){
try{
let then = promise3.then;
if(typeof then === 'function'){
then.call(promise3, (promise4)=>{
if(called) return;
called = true;
resolvePromiseRelation(promise3,promise4,resolve,reject);
},(r)=>{
if(called) return;
called = true;
reject(r);
});
}else{
resolve(promise3);
}
}catch(e){
if(called) return;
called = true;
reject(e);
};
}else{
resolve(promise3);
}
}
Promise.prototype.catch = function(errFn){
return this.then(null,errFn);
}
Promise.prototype.finally = function(fn){
this.then(()=>{
fn();
},()=>{
fn();
});
return this;
}
Promise.all = function(values){
return new Promise((resolve,reject)=>{
let results = [];
let index = 0;
function addToArr(key,value){
index++;
results[key] = value;
if(index === values.length){
resolve(results);
}
}
for(let i = 0; i < values.length; i++){
let current = values[i];
if(current && current.then && typeof current.then === 'function'){
current.then((value)=>{
addToArr(i,value);
},reject);
}else{
addToArr(i,current);
}
}
});
}
Promise.race = function(values){
return new Promise((resolve,reject)=>{
for(let i = 0; i < values.length; i++){
let current = values[i];
if(current&¤t.then&&typeof current.then === 'function'){
current.then(resolve,reject);
}else{
resolve(current);
}
}
});
}
Promise.resolve = function(value){
return new Promise((resolve,reject)=>{
resolve(value);
});
}
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
reject(reason);
});
}
// 实现一个promise的延迟对象 defer
Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve, reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
源码在github上,写文章不易,欢迎star或fork,thx~github
来自:https://segmentfault.com/a/1190000018209663
Promise 想必大家十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。
本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定.
Async/Await替代Promise的6个理由:Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一,Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数
这篇文章是考虑如何自己实现一个简单 Promise,用以理解 Promise。和原生 Promise的调用方法一样,支持链式调用,本文实现的方法只能用于参考Promise的原理,还有很多特性没有实现,比如 race,all 方法的实现。
在对数组进行一些遍历操作时,发现有些遍历方法对Promise的反馈并不是我们想要的结果。async/await为Promise的语法糖,文中会直接使用async/await替换Promise;map可以说是对Promise最友好的一个函数了,
最近在使用axios库时遇到了个问题,后端接口报了500错误,但前端并未捕获到。在axios整体配置的代码中,过滤http code时,调用了filter401()、filter500(),但是这里注意并未将两个filter函数的结果返回,也就是并未返回promise,这就是导致问题出现的原因
想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行
你可以在 .then 里面 return 一个 Promise,每次执行 .then 的时候都会自动创建一个新的 Promise,对调用者来说,Promise 的 resolved/rejected 状态是唯一的,Promise 构造函数不是解决方案,使用 Promise.resolve
首先来分析一下then then是属于实例上的方法 参数有2个,分别为onFulfilled, onRejected,并且都是可选的、可以实现链式调用、then执行要执行Promise onFulfilled 或者 onRejected 方法、参数onFulfilled,onRejected 分别有自己的参数, 分别是resolve的参数跟reject的参数、then只能使用前一个then的返回值、then返回值不能是同一个promise
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!