Promise
- Promise是一个类,一种异步解决方案
- 每一个Promise有三个状态Pedding,fulfilled, rejected,当处于pedding状态时,可以转为fufilled或者rejected态,但一但fufilled或者rejected,状态不可改变
- 每个promise实例都有一个then方法,参数有成功的回调或者失败的回调
- Promise有一些静态方法,如finally,all,race,reslove,rejected
- 值的穿透
手动实现promise
const RESOLVED = 'RESOLVED'; // 成功
const REJECTED = 'REJECTED'; // 失败
const PENDING = 'PENDING'; // 等待态
// promise就是一个类
// 1.promise 有三个状态: 成功态(resolve) 失败态(reject) 等待态(pending) (又不成功又不失败)
// 2.用户自己决定失败的原因和成功的原因 成功和失败也是用户定义的
// 3.promise 默认执行器时立即执行
// 4.promise的实例都拥有一个then方法 , 一个参数是成功的回调,另一个失败的回调
// 5.如果执行函数时发生了异常也会执行失败逻辑
// 6.如果promise一旦成功就不能失败 , 反过来也是一样的 (只有等待态的时候才能去更改状态)
// resolvePromise 所有的promise都要坚持 bluebird q es6-promise
const resolvePromise = (promise2, x, resolve, reject) => {
// 1.循环引用 自己等待自己完成 错误的实现
if (promise2 === x) { // 用一个类型错误 结束掉promise
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 后续的条件要严格判断 保证代码能和别的库一起使用
let called;
if ((typeof x === 'object' && x != null) || typeof x === 'function') { // 有可能是一个promise
// 要继续判断
try {
let then = x.then;
if (typeof then === 'function') { // 只能认为是一个promise了
// 不要写成x.then 直接then.call就可以了 因为x.then 会再次取值
then.call(x, y => { // 根据promise的状态决定是成功还是失败
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject); // 递归解析的过程
}, e => {
if (called) return;
called = true;
reject(e); // 只要失败就失败
});
} else { // {then:'23'}
resolve(x);
}
} catch (e) { // 防止失败了再次进入成功
if (called) return;
called = true;
reject(e); // 取值出错
}
} else {
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = []; // 专门用来存放成功的回调
this.onRejectedCallbacks = []; // 专门用来存放失败的回调
let resolve = (value) => { // 调用此方法就是成功
if(value instanceof Promise){
return value.then(resolve,reject); // 递归解析resolve中的参数,直到这个值是普通值
}
if (this.status === PENDING) {
this.value = value;
this.status = RESOLVED;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject); // 立即执行
} catch (e) { // 错误处理 需要直接走错误逻辑
reject(e);
}
}
// 1. promise 成功和失败的回调的返回值 可以传递到外层的下一个then
// 2. 如果返回的是普通值的话 (传递到下一次的成功中,不是错误不是promise就是普通值) ,出错的情况(一定会走到下一次的失败),可能还要promise的情况(会采用promise的状态,决定走下一次的成功还是失败 )
// 3.错误处理 如果离自己最近的then 没有错误处理(没有写错误函数) 会向下找
// 4. 每次执行完promise.then方法后返回的都是一个“新的promise (promisey一旦成功或者失败就不能修改状态)
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => { // 为了实现链式调用
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// x可能是一个proimise
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
// todo...
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
// todo...
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
}
module.exports = Promise;
prototype上的方法
finally方法
... 省略
finally(fn) {
this.then((value) => {
return Promise.resolve(fn).then(() => value)
}, (resaon) => {
return Promise.resolve(fn).then(() => {throw reason})
})
}
...
catch
...省略
catch(callback) {
this.then(null, callback)
}
...
静态方法
all
...省略
static all(arr) {
// 如果是promise,则调用then方法将结果返回,如果是值,则直接resolve
let count = 0
let result = []
// 都执行后将结果传递
function handleData(v, index, resolve, reject) {
if ((v!==null && typeof v === 'object') || typeof v === 'function') {
// promise
v.then((currentValue) => {
handleData(currentValue, index, resolve, reject)
}, reject)
} else {
result[index] = v
count++
}
if (count === arr.length) {
resolve(result)
}
}
return new Promise(function(resolve, reject) {
arr.forEach((value, index) => {
handleData(value, index, resolve, reject)
})
})
}
race
...省略
static race(arr) {
return new Promise1(function(resolve, reject) {
arr.forEach(value => {
let then = value.then
if (then && typeof then === 'function') {
then.call(value, v => {
resolve(v)
}, reject)
} else {
resolve(value)
}
})
})
}
...
resolve
...省略
static resolve(value) {
return new Promise(function(resolve, reject) {
resolve(value)
})
}
...
reject
...省略
static reject(reason) {
return new Promise(function(resolve, reject) {
reject(reason)
})
}
...
测试
...省略
// promise的延迟对象
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd
}
...
- npm install promises-aplus-test -g
- promises-aplus-test promise.js
最大并发
const imglist = ['https://xxx.problem.png',
'https://xxx.counter.png',
'https://xxx.mall_banner.png',
'https://xxx.turn_table.png',
'https://xxx.answer.png',
'https://xxx.turn_table.png',
'https://xxx.ICBC.png']
const loadimg = (url) => new Promise((reslove, reject) => {
const img = new Image()
img.onload = () => {
reslove()
}
img.onerror = reject
img.src = url
})
const loadimglimit = (urls, handler, limit) => {
const awaitQueue = [].concat(urls)
let promises = [];
promises = awaitQueue.splice(0, limit).map((url, index) => loadimg(url).then(() => index));
(async () => {
let p = Promise.race(promises) // 返回最先执行的promise,使用then会打印出他的value
awaitQueue.forEach((task, idx) => {
p = p.then((index) => {
promises[index] = handler(awaitQueue[idx]).then(() => {
return index
});
console.log(promises, task, 'promises')
return Promise.race(promises)
})
})
})()
}
loadimglimit(imglist, loadimg, 3)
promise的中断
- 借助race的特点,可以实现立即中断promise变为失败态。常用作超时操作
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 3000);
})
function wrap(p){
let abort;
let p1 = new Promise((resolve,reject)=>{
abort = reject;
});
let newPromise = Promise.race([p1,p])
newPromise.abort = abort
return newPromise
}
let p1 = wrap(p);
p1.then(data => {
console.log('success', data)
}, err => {
console.log('error', err)
})
setTimeout(() => {
p1.abort('超过2s了');
}, 2000);
promiseify
function promisify(fn){
return function (...args) {
return new Promise((resolve,reject)=>{
fn(...args,function (err,data) {
if(err) reject();
resolve(data);
})
});
}
}
let read = promisify(fs.readFile);
co库原理
function co(it){
return new Promise((resolve,reject)=>{
function next(data){
let {value,done} = it.next(data);
if(!done){
Promise.resolve(value).then(data=>{
next(data);
},reject)
}else{
resolve(value);
}
}
next();
});
}