Promise详解与实现

1.什么是Promise?

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一

2.对于几种常见异步编程方案

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise对象
这里就拿回调函数说说

1.对于回调函数 我们用Jquery的ajax获取数据时 都是以回调函数方式获取的数据

$.get(url, (data) => {
console.log(data)
)

2.如果说 当我们需要发送多个异步请求 并且每个请求之间需要相互依赖 那这时 我们只能 以嵌套方式来解决 形成 “回调地狱”

$.get(url, data1 => {
console.log(data1)
$.get(data1.url, data2 => {
    console.log(data1)
})
})

这样一来,在处理越多的异步逻辑时,就需要越深的回调嵌套,这种编码模式的问题主要有以下几个:

  • 代码逻辑书写顺序与执行顺序不一致,不利于阅读与维护。
  • 异步操作的顺序变更时,需要大规模的代码重构。
  • 回调函数基本都是匿名函数,bug 追踪困难。
  • 回调函数是被第三方库代码(如上例中的 ajax )而非自己的业务代码所调用的,造成了 IoC 控制反转。
Promise 处理多个相互关联的异步请求

1.而我们Promise 可以更直观的方式 来解决 “回调地狱”

const request = url => {
return new Promise((resolve, reject) => {
    $.get(url, data => {
        resolve(data)
    });
})
};

// 请求data1
request(url).then(data1 => {
return request(data1.url);   
}).then(data2 => {
return request(data2.url);
}).then(data3 => {
console.log(data3);
}).catch(err => throw new Error(err));

2.相信大家在 vue/react 都是用axios fetch 请求数据 也都支持 Promise API

import axios from 'axios';
axios.get(url).then(data => {
console.log(data)
})

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

3.Promise使用

1.Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject
const promise = new Promise((resolve, reject) => {
   // 异步处理
   // 处理结束后、调用resolve 或 reject
});
2.promise相当于一个状态机

promise的三种状态
- pending
- fulfilled
- rejected

1.promise 对象初始化状态为 pending
const promise = new Promise;
2.当调用resolve(成功),会由pending => fulfilled
3.当调用reject(失败),会由pending => rejected

注意promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变

3.promise对象方法

1.then方法注册 当resolve(成功)/reject(失败)的回调函数

// onFulfilled 是用来接收promise成功的值
// onRejected 是用来接收promise失败的原因
promise.then(onFulfilled, onRejected);

then方法是异步执行的

2.resolve(成功) onFulfilled会被调用

const promise = new Promise((resolve, reject) => {
resolve('fulfilled'); // 状态由 pending => fulfilled
});
promise.then(result => { // onFulfilled
console.log(result); // 'fulfilled'
}, reason => { // onRejected 不会被调用

})

3.reject(失败) onRejected会被调用

const promise = new Promise((resolve, reject) => {
reject('rejected'); // 状态由 pending => rejected
});
promise.then(result => { // onFulfilled 不会被调用

}, reason => { // onRejected
console.log(rejected); // 'rejected'
})

4.promise.catch

在链式写法中可以捕获前面then中发送的异常,

promise.catch(onRejected)
相当于
promise.then(null, onRrejected);

// 注意
// onRejected 不能捕获当前onFulfilled中的异常
promise.then(onFulfilled, onRrejected);

// 可以写成:
promise.then(onFulfilled)
   .catch(onRrejected);   
4.promise chain

promise.then方法每次调用 都返回一个新的promise对象 所以可以链式写法

function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}

var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected) // 捕获前面then方法中的异常
5.Promise的静态方法

1.Promise.resolve 返回一个fulfilled状态的promise对象

Promise.resolve('hello').then(function(value){
console.log(value);
});

Promise.resolve('hello');
// 相当于
const promise = new Promise(resolve => {
resolve('hello');
});

2.Promise.reject 返回一个rejected状态的promise对象

Promise.reject(24);
new Promise((resolve, reject) => {
reject(24);
});

3.Promise.all 接收一个promise对象数组为参数

只有全部为resolve才会调用 通常会用来处理 多个并行异步操作

const p1 = new Promise((resolve, reject) => {
resolve(1);
});

const p2 = new Promise((resolve, reject) => {
resolve(2);
});

const p3 = new Promise((resolve, reject) => {
reject(3);
});

Promise.all([p1, p2, p3]).then(data => {
console.log(data); // [1, 2, 3] 结果顺序和promise实例数组顺序是一致的
}, err => {
console.log(err);
});

4.Promise.race 接收一个promise对象数组为参数

Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。

function timerPromisefy(delay) {
return new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(delay);
    }, delay);
});
}
var startDate = Date.now();

Promise.race([
timerPromisefy(10),
timerPromisefy(20),
timerPromisefy(30)
]).then(function (values) {
console.log(values); // 10
});

4. Promise 代码实现

// 定义三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function Promise(executor) {
let that = this; // 缓存当前promise实例
that.status = PENDING; // 设置初始状态
// 定义存放成功的回调的数组
that.onResolvedCallbacks = [];
// 定义存放失败回调的数组
that.onRejectedCallbacks = [];

// resolve被调用 promise 状态会由 pending => fulfilled
function resolve(value) {
    if (value != null && value.then && typeof value.then == 'function') { /
        return value.then(resolve, reject);
    }
    // 只能由pending状态转换为fulfilled 并将成功态结果传递给onFulfilled
    setTimeout(function() {
        if (that.status == PENDING) {
            that.status = FULFILLED;
            that.value = value; // 成功后会得到一个值,这个值不能改
            // 调用所有成功的回调
            that.onResolvedCallbacks.forEach(cb => cb(that.value));
        }
    })

}

// resolve被调用 promise 状态会由 pending => ejected 并将拒绝原因传递给onRejected
function reject(reason) {
    setTimeout(function() {
        // 只能由pending状态转换为rejected
        if (that.status == PENDING) {
            that.status = REJECTED;
            that.value = reason; //失败的原因给了value
            that.onRejectedCallbacks.forEach(cb => cb(that.value));
        }
    });

}
try {
    // executor函数执行可能会异常,所以需要捕获
    executor(resolve, reject);
} catch (e) { // 如果异常则修改promise状态为rejected 并将异常信息传递进去
    reject(e);
};
}


// onFulfilled的返回值几种情况
// 1.普通值
// 2.thenable对象
// 3.函数
// 4.promsie对象

// onFulfilled 的返回值情况处理函数
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
    return reject(new TypeError('循环引用'));
}
let called = false; // promise2是否已经resolve 或reject了
if (x instanceof Promise) {
    if (x.status == PENDING) {
        x.then(function(y) { // 继续解析这个x的onFulfilled返回值
            resolvePromise(promise2, y, resolve, reject);
        }, reject);
    } else {
        x.then(resolve, reject);
    }
    // x是一个thenable对象或函数,只要有then方法的对象,
} else if (x != null && ((typeof x == 'object') || (typeof x == 'function'))) {
    // 当我们的promise和别的promise进行交互,编写这段代码的时候尽量的考虑兼容性,允许别人瞎写
    try {
        let then = x.then;
        if (typeof then == 'function') {
            // 有些promise会同时执行成功和失败的回调
then.call(x, function(y) {
                // 如果promise2已经成功或失败了,则不会再处理了
                if (called)
                    return;
                called = true;
                resolvePromise(promise2, y, resolve, reject)
            }, function(err) {
                if (called)
                    return;
                called = true;
                reject(err);
            });
        } else {
            // 如果x是一个普通对象直接resolve
            resolve(x);
        }
    } catch (e) {
        if (called)return;
        called = true;
        reject(e);
    }

} else {
    // 如果X是一个普通 的值,则用x的值去resolve promise2
    resolve(x);
}
}
// onFulfilled 是用来接收promise成功的值或者失败的原因

// then方法是异步的 每次调用都会返回一个新的promise 从而实现方法链
Promise.prototype.then = function(onFulfilled, onRejected) {
// 如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛
onFulfilled = typeof onFulfilled == 'function'
    ? onFulfilled
    : function(value) {
        return value
    };
onRejected = typeof onRejected == 'function'
    ? onRejected
    : reason => {
        throw reason
    };
// 如果当前promise状态已经是成功态了,onFulfilled直接取值
let that = this;
let promise2;

if (that.status == FULFILLED) {
    return promise2 = new Promise(function(resolve, reject) {
        setTimeout(function() { // 异步调用
            try {
                let x = onFulfilled(that.value);
                // 如果获取到了返回值x,会走解析promise的过程
                resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
                //如果执行成功的回调过程中出错了,用错误原因把promise2 reject
                reject(e);
            }
        })

    });
}

if (that.status == REJECTED) {
    return promise2 = new Promise(function(resolve, reject) {
        setTimeout(function() { // 异步调用
            try {
                let x = onRejected(that.value);
                resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
                reject(e);
            }
        })
    });
}

if (that.status == PENDING) { // 异步调用
    return promise2 = new Promise(function(resolve, reject) {
        that.onResolvedCallbacks.push(function() {
            try {
                let x = onFulfilled(that.value);
                // 如果获取到了返回值x,会走解析promise的过程
                resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
                reject(e);
            }

        });
        that.onRejectedCallbacks.push(function() {
            try {
                let x = onRejected(that.value);
                resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
                reject(e);
            }
        });
    });
}

}
//catch原理就是只传失败的回调
Promise.prototype.catch = function(onRejected) {
this.then(null, onRejected);
}

// Deferred 延迟对象
// Deferred 拥有 Promise
// Deferred 具备对 Promise的状态进行操作的特权方法
// 想了解 可以看看 jQuery.Deferred
Promise.deferred = Promise.defer = function() {
let defer = {};
defer.promise = new Promise(function(resolve, reject) {
    defer.resolve = resolve;
    defer.reject = reject;
});
return defer;
}
function gen(times, cb) {
let result = [],
    count = 0;
return function(i, data) {
    result[i] = data;
    if (++count == times) {
        cb(result);
    }
}
}

// all 方法实现
Promise.all = function(promises) {
return new Promise(function(resolve, reject) {
    let done = gen(promises.length, resolve);
    for (let i = 0; i < promises.length; i++) {
        promises[i].then(function(data) {
            done(i, data);
        }, reject);
    }
});
}

// race 方法实现
Promise.race = function(promises) {
return new Promise(function(resolve, reject) {
    for (let i = 0; i < promises.length; i++) {
        promises[i].then(resolve, reject);
    }
});
}
// 返回一个立刻成功的promise
// 别人提供 给你一个方法,需要你传入一个promise,但你只有一个普通的值,你就可以通过这个方法把这个普通的值(string number object)转成一个promise对象
Promise.resolve = function(value) {
return new Promise(function(resolve) {
    resolve(value);
});
}
// 返回一个立刻失败的promise
Promise.reject = function(reason) {
return new Promise(function(resolve, reject) {
    reject(reason);
});
}
module.exports = Promise;

Promise测试

npm i -g promises-aplus-tests
promises-aplus-tests Promise.js

相关知识参考资料

  • [ES6-promise](ECMAScript 6入门)
  • Promises/A+规范-英文
  • [Promises/A+规范-翻译](人类身份验证 - SegmentFault)
  • [Javascript异步编程的4种方法](Javascript异步编程的4种方法 - 阮一峰的网络日志)
  • Lwenli_blog
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值