第十八题:请实现 Promise.all
KieSun opened this issue · comments
Promise.all = function(arr) {
if(!Array.isArray(arr)) {
throw new Error('参数必须是数组')
}
return new Promise((resolve, reject) => {
const list = []
arr.forEach(item => {
this.resolve(item).then((value) => {
list.push(value)
if(list.length === arr.length) {
resolve(list)
}
}, (err)=> {
reject(err)
})
})
})
}
Promise.All = function (arg) {
if (!Array.isArray(arg)) {
return Promise.reject(new Error('参数必须是数组'))
}
return new Promise((resolve, reject) => {
let count = 0;
const totalCount = arg.length
const results = []
arg.forEach((item, index) => {
const ret = item?.then ? item : Promise.resolve(item)
ret.then(result => {
count++
results[index] = result
if (count === totalCount) {
resolve(results)
}
}).catch(error => {
reject(error)
})
})
})
}
const request = (data) => new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.9) {
resolve(data)
} else {
reject(data)
}
}, 2000 * Math.random());
})
Promise.All([1, 2, 3, request(4)]).then(ret => {
console.log("ret2", ret)
}).catch(error => {
console.error("error2", error)
})
// ret2 (4) [1, 2, 3, 4]
Promise.All(new Array(10).fill(null).map((e, i) => request(i))).then(ret => {
console.log("ret", ret)
}).catch(error => {
console.error("error", error)
})
// ret (10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Promise.all = function(arr) { if(!Array.isArray(arr)) { throw new Error('参数必须是数组') } return new Promise((resolve, reject) => { const list = [] arr.forEach(item => { this.resolve(item).then((value) => { list.push(value) if(list.length === arr.length) { resolve(list) } }, (err)=> { reject(err) }) }) }) }
@learnRy 返回结果顺序不对
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
class MyPromise {
constructor(callback) {
this.status = PENDING;
this.value = null;
this.resolvedCB = [];
this.rejectedCB = [];
callback(this.resolve.bind(this), this.reject.bind(this));
}
resolve(data) {
this.value = data;
this.status = RESOLVED;
this.resolvedCB.forEach((cb) => {
this.value = cb(this.value);
});
this.resolvedCB = [];
}
reject(data) {
this.value = data;
this.status = REJECTED;
this.rejectedCB.forEach((cb) => {
this.value = cb(this.value);
});
this.rejectedCB = [];
}
then(handleResolved, handleRejected) {
handleResolved && this.resolvedCB.push(handleResolved);
handleRejected && this.rejectedCB.push(handleRejected);
if (this.status === RESOLVED) {
this.resolvedCB.forEach((cb) => {
this.value = cb(this.value);
});
this.resolvedCB = [];
}
if (this.status === REJECTED) {
this.rejectedCB.forEach((cb) => {
this.value = cb(this.value);
});
this.rejectedCB = [];
}
}
}
MyPromise.all = function (promises) {
const allData = [];
return new MyPromise((resolve, reject) => {
const run = () => {
if (promises.length === 0) return;
const promise = promises.shift();
if (promise) {
promise.then((data) => {
allData.push(data);
if (promises.length === 0) {
resolve(allData);
} else {
run();
}
});
}
};
run();
});
};
// test
const a = new MyPromise((resolve) => {
setTimeout(() => resolve("a"), 200);
});
const b = new MyPromise((resolve) => {
setTimeout(() => resolve("b"), 800);
});
const c = new MyPromise((resolve) => {
setTimeout(() => resolve("c"), 100);
});
MyPromise.all([a, b, c]).then((data) => console.log("allData", data));
// ["a", "b", "c"]
const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; class MyPromise { constructor(callback) { this.status = PENDING; this.value = null; this.resolvedCB = []; this.rejectedCB = []; callback(this.resolve.bind(this), this.reject.bind(this)); } resolve(data) { this.value = data; this.status = RESOLVED; this.resolvedCB.forEach((cb) => { this.value = cb(this.value); }); this.resolvedCB = []; } reject(data) { this.value = data; this.status = REJECTED; this.rejectedCB.forEach((cb) => { this.value = cb(this.value); }); this.rejectedCB = []; } then(handleResolved, handleRejected) { handleResolved && this.resolvedCB.push(handleResolved); handleRejected && this.rejectedCB.push(handleRejected); if (this.status === RESOLVED) { this.resolvedCB.forEach((cb) => { this.value = cb(this.value); }); this.resolvedCB = []; } if (this.status === REJECTED) { this.rejectedCB.forEach((cb) => { this.value = cb(this.value); }); this.rejectedCB = []; } } } MyPromise.all = function (promises) { const allData = []; return new MyPromise((resolve, reject) => { const run = () => { if (promises.length === 0) return; const promise = promises.shift(); if (promise) { promise.then((data) => { allData.push(data); if (promises.length === 0) { resolve(allData); } else { run(); } }); } }; run(); }); }; // test const a = new MyPromise((resolve) => { setTimeout(() => resolve("a"), 200); }); const b = new MyPromise((resolve) => { setTimeout(() => resolve("b"), 800); }); const c = new MyPromise((resolve) => { setTimeout(() => resolve("c"), 100); }); MyPromise.all([a, b, c]).then((data) => console.log("allData", data)); // ["a", "b", "c"]
这个MyPromise不符合Promise/A+规范
- 1.输入是一个每一项是Promise的iterable类型数据(Array,Set,Map)
- 2.输出是一个新的Promise实例value(2种情况 reslove一个数组 或reject第一个错误)
- 3.要做的工作:检查是否传入的为数组,检查传入的每一项是否为Promise实例,创建一个新的Promise实例A,将输入的每一个Promise实例都执行,获取resolve的value,并组成一个数组Arr,作为新创建Promise实例A的reslove的对象,如果其中有不合法的错误或者reject,Promise实例A会立即抛出第一个错误
function _all(arr) {
//数组类型检查
if (!Array.isArray(arr)) {
throw new TypeError('is not Array')
}
return new Promise(function (reslove, reject) {
try {
let result = []
for (let item of arr) {
//检查实例是否为Promises实例
if (Object.prototype.toString.call(item).indexOf("Promise") == -1) {
//没有的话返回当前值(为了保证按顺序执行,自己封装一个Promise实例)
item = new Promise(function (reslove, reject) {
reslove(item)
})
}
item.then((res, err) => {
if (err) {
throw new Error(err)
} else {
result.push(res)
if (arr.indexOf(item) == arr.length - 1) {
reslove(result)
}
}
})
}
} catch (error) {
reject(error)
}
})
}
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
const promise4 = function name(params) {
};
_all([promise2, promise1, promise4,promise3]).then(res => {
console.log(res, 'cc');
})
//[ 42, 3, [Function: name], 'foo' ] cc
function promiseAll(list) {
if (!Array.isArray(list)) {
throw new Error('参数错误')
}
const result = []
const n = list.length
let successCount = 0
list.forEach((item, index) => {
item.then(res => {
result[index] = res
successCount++
if (n === successCount) {
return Promise.resolve(result)
}
}).catch(e => {
return Promise.reject(e)
})
})
}
// 请实现 Promise.all
Promise.all = (arr) => {
const length = arr.length;
const result = [];
let count = 0;
return new Promise((resolve, reject) => {
arr.forEach((item, index) => {
if (item instanceof Promise) {
item.then(
(res) => {
result[index] = res;
count += 1;
if (count === length) resolve(result);
},
(error) => {
reject(error);
}
);
} else {
result[index] = item;
count += 1;
if (count === length) resolve(result);
}
});
});
};
代码实现
Promise.myAll = function (promises) {
let count = 0;
return new Promise((resolve, reject) => {
let result = new Array(promises.length);
for (let i = 0; i < promises.length; i += 1) {
const promise = promises[i];
if (promise instanceof Promise) {
promise
.then((res) => {
result[i] = res;
count += 1;
if (count === promises.length) {
resolve(result);
}
})
.catch((err) => {
reject(err);
});
} else {
result[i] = promise;
count += 1;
if (count === promises.length) {
resolve(result);
}
}
}
});
};
测试用例
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve('hello');
}, 1000);
});
const p2 = new Promise((resolve) => {
setTimeout(() => {
resolve('world');
}, 500);
});
const p3 = 999;
const p4 = Promise.reject('this is an error');
Promise.myAll([p1, p2, p3]).then((res) => {
console.log(`res: `, res);
});
// res: [ 'hello', 'world', 999 ]
Promise.myAll([p1, p2, p3, p4])
.then((res) => {
console.log(`res: `, res);
})
.catch((error) => {
console.log(`error: `, error);
})
// error: this is an error
Promise.all
思路:
- 返回一个新的
Promise
- 当且仅当所有异步任务完成时
resolve
- 只要有一个异步任务异常,则直接
reject
Promise.myAll = function (array) {
if (!Array.isArray(array)) {
return Promise.reject(new Error("Error: The params must be an Array"));
}
return new Promise((resolve, reject) => {
let count = 0;
let result = [];
array.forEach((element, index) => {
const isPromise = element instanceof Promise;
const promise = isPromise ? element : Promise.resolve(element);
promise
.then((res) => {
count = count + 1;
result[index] = res;
if (array.length === count) {
resolve(result);
}
})
.catch((error) => reject(error));
});
});
};
Tips:
instanceof Promise
判断是否为 PromiseArray.isArray
判断是否为数组
刚好最近试着封装了下promise
const ENUM = {
PENDING: 'PENDING',
FULFILLED: 'FULFILLED',
REJECTED: 'REJECTED'
}
const resolvePromise = (x, promise2, resolve, reject) => {
if (x === promise2) {
reject(new TypeError(`Chaining cycle detected for promise #<Promise>`))
}
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let called
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if(called) return
called = true
resolvePromise(y, promise2, resolve, reject)
}, r => {
if(called) return
called = true
reject(r)
})
} else {
resolve(x)
}
} catch (e) {
if(called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = ENUM.PENDING
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.status === ENUM.PENDING) {
this.status = ENUM.FULFILLED
this.value = value
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === ENUM.PENDING) {
this.status = ENUM.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
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 === ENUM.FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
},0)
} else if (this.status === ENUM.REJECTED) {
setTimeout(() => {
try{
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
},0)
} else if (this.status === ENUM.PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
},0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
},0)
})
}
})
return promise2
}
catch(errCallback) {
return this.then(null, errCallback)
}
static resolve = (val) => {
return new Promise((resolve, reject) => {
resolve(val)
})
}
static reject = (r) => {
return new Promise((resolve, reject) => {
reject(r)
})
}
static all = (values) => {
return new Promise((resolve, reject) => {
let resultArr = []
let orderIndex = 0
const processResultByKey = (value, index) => {
resultArr[index] = value
if( ++orderIndex === values.length) resolve(resultArr)
}
for (let i = 0; i < values.length; i++) {
let value = values[i]
if (value && typeof value.then === 'function') {
value.then(value => {
processResultByKey(value, i)
},reject)
} else {
processResultByKey(value, i)
}
}
})
}
}
Promise.prototype.defer = Promise.deferred = () => {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
Promise.prototype.finally = callback => {
return this.then(value => {
return Promise.resolve(callback().then(() => value))
}, err => {
return Promise.resolve(callback().then(() => {throw err}))
})
}
Promise.MyAll = function(pArr) {
const length = pArr.length
if (!Array.isArray(pArr)) {
throw new Error('参数必须是数组')
}
return new Promise((resolve, reject) => {
let res = Array(length).fill(), count = 0
pArr.forEach((p, idx) => {
p = p instanceof Promise ? p : Promise.resolve(p)
p.then((data) => {
count++
res[idx] = data
if (count === length) {
resolve(res)
}
}).catch(err => {
reject(err)
})
})
})
}
function fn(data) {
return new Promise((resolve, reject) => {
Math.random() < 0.7 ? resolve(data) : reject(`${data}`)
}, Math.random() * 2000)
}
Promise.MyAll([0, fn(1), fn(3), 3]).then((data) => {
console.log('data', data)
}).catch((err) => {
console.log('err', err)
})
实现一个Promise.all 功能
Promise.all 是传入xxx 返回xxx
Promise.all() 方法接收一个promise的 iterable 类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'three');
});
var p4 = new Promise((resolve, reject) => {
setTimeout(resolve, 4000, 'four');
});
var p5 = new Promise((resolve, reject) => {
reject('reject');
});
Promise.all([p1, p2, p3, p4, p5]).then(values => {
console.log(values);
}, reason => {
console.log(reason)
});
//From console://"reject"
具体实现方式
// 判断该数组中的内容是否为 Promise
const isPromise = obj =>
!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
function promiseAll(target) {
// 判断传入的是否为 iterable 类型的数据
if (Array.from(target) instanceof Array) {
// 核心逻辑 按照数组的顺序,依次执行并返回数组中
return new Promise(async function (resolve, reject) {
try {
let result = []; // 保存最后返回结果的数组
for (let i = 0; i < target.length; i++) {
if (isPromise(target[i])) { // 判断是否为 Promise类型
// 如果其中一个 Promise 出现错误了 直接就返回 不再执行后面的内容
const answer = await target[i];
result.push(answer);
} else {
result.push(target[i]); // 直接存到数组中
}
}
resolve(result);
} catch (err) {
reject(err);
}
})
} else {
throw new TypeError(typeof target + target + 'is not iterable (cannot read property Symbol(Symbol.iterator))'); // 返回类型错误 例如 boolean 类型不能进行枚举
}
}
const p1 = Promise.reject(3);
const p2 = 42;
const p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
promiseAll([p1, p2, p3]).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
疑问
- 怎么在同步的代码里面获取到 Promise的状态?目前使用的方法是 await 但是感觉不太优雅而且容易出问题
function PromiseAll(promiseArray) {
return new Promise(function(resolve, reject) {
if(!Array.isArray(promiseArray)){
return reject(new TypeError("参数必须是数组"));
}
let resolveArray = [],
count = 0;
promiseArray.forEach((item, index) => {
Promise.resolve(item).then((res) => {
count++;
resolveArray[index] = res;
if(count == promiseArray.length){
resolve(resolveArray);
}
}).catch(err => {
reject(err);
})
})
})
}
const p1 = new Promise((resolve, reject) => {
let num = 1;
setTimeout(() => {
resolve(num)
}, 3000);
});
const p2 = 3;
const p3 = Promise.resolve(4);
const p4 = setTimeout(() => {
console.log('sdffsd')
}, 2000);
const p5 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5)
}, 3000);
})
Promise.myAll = (args) => {
if(!Array.isArray(args)){
throw new Error('参数必须是数组')
}
return new Promise((resolve, reject) => {
let result = [];
for(let i = 0, len = args.length; i < len; i++) {
Promise.resolve(args[i]).then(res => {
result.push(res);
if(result.length === len) {
resolve(result)
}
}, (err) => {
reject(err);
})
}
});
}
const p6 = new Promise((resolve, reject) => {
let num = 1;
setTimeout(() => {
if(num === 1) reject('num 不能为1')
}, 3000);
});
Promise.myAll([p1,p2, p3, p4, p5]).then(res => {
console.log(res, 'promise all resolve')
}, (err) => {
console.log(err, 'promise all rejected')
});
// 执行结果
// Array(5) [3, 4, 87, 1, 5] "promise all resolve"
Promise.myAll([p2, p3, p4, p5, p6]).then(res => {
console.log(res, 'promise all resolve')
}, (err) => {
console.log(err, 'promise all rejected')
});
// 执行结果
// num 不能为1 promise all rejected
Promise.myAll = function (arr) {
if (!Array.isArray(arr)) {
throw new Error("参数必须为数组");
}
return new Promise((resolve, reject) => {
let result = [];
arr.forEach((p, index) => {
p = p.then ? p : Promise.resolve(p)
p.then((res) => {
result[index] = res;
if (result.length === arr.length) {
resolve(result);
}
}).catch((err) => reject(err));
});
});
};
const isIterable = (obj) => {
return obj != null && typeof obj[Symbol.iterator] === "function";
};
Promise.all1 = function (arr) {
if (!isIterable(arr)) {
throw new TypeError(typeof arr + " " + arr + " " + "is not iterable");
}
return new Promise((resolve, reject) => {
let resolvedArr = [];
let resolvedCount = 0;
for (let [index, value] of arr.entries()) {
((index, value) => {
Promise.resolve(value).then(
(res) => {
resolvedCount++;
resolvedArr[index] = res;
if (resolvedCount === arr.length) {
resolve(resolvedArr);
}
},
(err) => {
reject(err);
}
);
})(index, value);
}
});
};
let p1 = Promise.resolve(3);
let p2 = 1337;
let p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "foo");
});
let p = Promise.all1([p1, p2, p3]).then((values) => {
console.log("values", values); // [3, 1337, "foo"]
});
function myPromiseAll(params) {
if (Array.isArray(params)) {
let pros = [].concat(params);
let limitLen = pros.length;
let doneCount = 0;
let result = [];
return new Promise((resolve, reject) => {
try {
let promises = pros.map((item, index) => {
return Promise.resolve(item).then((res) => {
return res;
});
});
for (let i = 0; i < promises.length; i++) {
promises[i].then((res) => {
result.push(res);
doneCount++;
if (doneCount == promises.length) {
resolve(result);
}
});
}
} catch (error) {
reject(error);
}
});
} else {
//其他iterable处理实现
}
}
const PENDING ='PENDING';
const RESOLVED = 'RESOLVED';
const REJECTED = 'REJECTED';
class PromiseA = function(executor) {
this.status = PENDING // 初始化状态
this.value = null // 成功回调
this.reason = null // 失败的回调
// 存储订阅的内容
this.onSuccessCallbacks = []; // success callback
this.onFulfillCallbacks = []; // fulfill callback
const resolve = (value) => {
if(this.status === 'PENDING'){
this.status = RESOLVED
this.value = value
this.onSuccessCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if(this.status === 'PENDING') {
this.status = REJECTED
this.reason = reason
this.onFulfillCallbacks.forEach(fn => fn())
}
}
// 同步 executor调用
try {
executor(resolve, reject)
} catch ( e ) {
// 报错直接抛出
reject(e)
}
then(onFulFilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (val) => val
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err
}
if(this.status === 'RESOLVED'){
onFulFilled(this.value)
}
if(this.status === 'REJECTED'){
onRejected(this.reason)
}
// 当Promise 里面有异步请求控制状态时,会先走到then 方法里面
// 把成功的回调和失败的回调先存储起来, 等到异步请求回来后变更状态,再触发执行
if(this.status === PENDING){
this.onSuccessCallbacks.push(() =>{
onFulfilled(this.value)
});
this.onFulfillCallbacks.push(() =>{
onRejected(this.value)
})
}
}
}
new PromiseA ((resolve, reject) =>{
setTimeout(() => {
resolve('中奖了~')
reject('再接再厉~')
}, 1000);
}).then((res) =>{
console.log('res', res)
}, (err) =>{
console.log('err',err)
})
只能实现一个 PromiseA , PromiseAll 暂时无法实现
Promise._all = function(promiseList = []) {
if(!Array.isArray(promiseList)) {
throw new TypeError('参数必须是数组')
}
return new Promise((resolve, reject) => {
let count = 0;
let res = []
promiseList.forEach((promise, index) => {
Promise.resolve(promise).then((value) => {
res[index] = value
count++
if(count === promiseList.length) {
resolve(res)
}
}, reject)
})
});
};
Promise._all([1, Promise.resolve(4)]).then(val => {
console.log('ok', val) // ok [ 1, 4 ]
}).catch(err => {
console.log('error', err)
})
Promise._all([1, Promise.resolve(4), Promise.reject(new Error('error'))]).then(val => {
console.log('ok', val)
}).catch(err => {
console.log('error', err) // error Error: error
})
class MyPromise {
constructor(executor) {
if (typeof executor != 'function') {
throw new Error('MyPromise must accept a function as a parameter')
}
//promise当前的状态
this.status = 'pending'
//promise的值
this.data = undefined
//promise resolve时的回调函数集,因为在promise结束之前可能有多个回调添加到它上面
this.onResolvedCallback = []
//promise reject时的回调函数集,因为在promise结束之前可能有多个回调添加到它上面
this.onRejectedCallback = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
// bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,例如,f.bind(obj),实际上可以理解为obj.f(),这时,f函数体内的this自然指向的是obj
// https://blog.csdn.net/qlwangcong518/article/details/86261597
} catch (err) {
this.reject(err)
}
}
resolve(value) {
if (this.status == 'pending') {
if (value instanceof MyPromise) {
value.then(res => {
this.status = 'fulfilled'
this.data = res
this.onResolvedCallback.forEach(callback => { callback(res) })
}, err => {
this.status = 'rejected'
this.data = err
this.onRejectedCallback.forEach(callback => { callback(err) })
})
} else {
this.status = 'fulfilled'
this.data = value
this.onResolvedCallback.forEach((callback) => { callback(value) })
}
}
}
reject(reason) {
if (this.status == 'pending') {
this.status = 'rejected'
this.data = reason
this.onRejectedCallback.forEach((callback) => {
callback(reason)
})
}
}
then(onResolved, onRejected) {
onResolved = onResolved instanceof 'function' ? onResolved : value => value
onRejected = onRejected instanceof 'function' ? onRejected : reason => reason
if (this.status === 'fulfilled') {
return new MyPromise((resolve, reject) => {
try {
let result = onResolved(this.data)
if (result instanceof MyPromise) {
result.then(resolve, reject)
}
resolve(result)
} catch (error) {
reject(error)
}
})
}
if (this.status === 'rejected') {
return new MyPromise((resolve, reject) => {
try {
let result = onRejected(this.data)
if (result instanceof MyPromise) {
result.then(resolve, reject)
}
resolve(result)
} catch (e) {
reject(e)
}
})
}
if (this.status === 'pending') {
return new MyPromise((resolve, reject) => {
this.onResolvedCallback.push((value) => {
try {
let result = onResolved(this.data)
if (result instanceof MyPromise) {
result.then(resolve, reject)
}
resolve(result)
} catch (e) {
reject(e)
}
})
this.onRejectedCallback.push((reason) => {
try {
let result = onRejected(this.data)
if (result instanceof MyPromise) {
result.then(resolve, reject)
}
resolve(result)
} catch (e) {
reject(e)
}
})
})
}
}
catch(onRejected) {
return this.then(null, onRejected)
}
all(iterators) {
let count = 0
let len = iterator.length
let res = []
return new MyPromise((resolve, reject) => {
for (const i in iterators) {
MyPromise.resolve(iterators[i])
.then((data) => {
res[i] = data
if (++count === len) {
resolve(res)
}
})
.catch(e => {
reject(e)
})
}
})
}
race(iterators) {
return new MyPromise((resolve, reject) => {
for (const p of iterators) {
MyPromise.resolve(p)
.then((res) => {
resolve(res)
})
.catch(e => {
reject(e)
})
}
})
}
}
使用fo of来遍历可迭代对象
let obj = {
a: 1,
b: 2,
[Symbol.iterator]: function*(){
yield 'iterator obj 1';
yield 'iterator obj 2';
yield 'iterator obj 3';
}
}
Promise.myAll = function(iterator){
return new Promise((resolve, reject) => {
let arr = []
let total = 0
let isDone = false
function success(res){
if(isDone){
return
}
arr.push(res)
total--
if(total <= 0) {
isDone = true
resolve(arr)
}
}
function faild(e){
if(isDone){
return
}
isDone = true
reject(e)
}
// 如果不是可迭代对象自会抛出错误
// 要兼容es6以下版本的需要判断是否为数组、字符串?
for(let value of iterator){
total++
Promise.resolve(value).then(success, faild)
}
})
}
testPromiseAll('abcdef')
testPromiseAll([1,2,3,4,5])
testPromiseAll(new Map([[1, 'Map1'], [2,'Map2']]))
testPromiseAll(new Set(['set1', 'set2']))
testPromiseAll([1,2,3,4,5])
testPromiseAll([sleep(100), sleep(200)])
testPromiseAll([sleep(100), sleep(200, true)])
testPromiseAll(obj)
function testPromiseAll(iterotor){
Promise.all(iterotor).then(res => {
console.log('Promise.all ', res)
}).catch(e => {
console.log('Promise.all ', e);
})
Promise.myAll(iterotor).then(res => {
console.log('Promise.myAll error', res);
}).catch(e => {
console.log('Promise.myAll error', e);
})
}
function sleep(time = 500, isFaild = false){
return new Promise((resolve, reject) => {
setTimeout(() => {
isFaild ? reject(new Error('mock error' + time)) : resolve('time: ' + time)
}, time)
})
}
Promise.all = (arr) => {
if (!Array.isArray(arr)) {
throw new TypeError("参数要是数组!");
}
var valuses = [];
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
// Promise.resolve()处理,确保每一个都是promise实例
Promise.resolve(arr[i]).then(
(val) => {
valuses[i] = val;
if (valuses.length === arr.length) resolve(valuses);
},
(err) => reject(err)
);
}
});
};
myPromise.prototype.all = function(params) {
if (!(params instanceof Array)) {
throw new Error('错误');
}
return new Promise((resolve, reject) => {
let res = [];
for (let i = 0; i < params.length; i++) {
params[i].then((data) => {
res[i] = data;
if (res.length === params.length) {
resolve(res);
}
}).catch((err) => {
reject(err);
});
}
});
}
// 传入一个数组,等数组的全部成功之后,返回一个Promise对象,成功回调全部返回的数组
Promise.myAll(arr) {
// 用于接收所有返回值
let result = [];
// 每次调用addData 这个index会加1 用index和传入数组的length比较 来解决异步函数的问题
let index = 0;
return new MyPromise((resolve, reject) => {
// 将数组中每一项添加到result数组中
function addData(key, value) {
result[key] = value;
index++;
if (index === arr.length) {
resolve(result);
}
}
for (let index = 0; index < arr.length; index++) {
let current = arr[index];
// 需要判断数组中的每一项是promise还是普通值
if (current instanceof MyPromise) {
// promise 对象
current.then(
(value) => addData(i, value),
(reason) => reject(reason)
);
} else {
//普通值
addData(i, current);
}
}
});
}
1、入参校验
2、保证执行为promise
3、保证执行结果的顺序
Promise.myAll = function (arr) {
if (!Array.isArray(arr)) {
throw new TypeError(`param is not Array`)
}
return new Promise((resolve, reject) => {
let len = arr.length;
let result = []
let count = 0
if (len === 0) {
return resolve(result)
}
for (let i in arr) {
Promise.resolve(arr[i]).then(data => {
result[i] = data
count++
if (count === len) {
resolve(result)
}
}).catch(e => {
reject(e)
})
}
})
}
function _PromissAll(promises) {
if (!Array.isArray(promises)) {
throw new TypeError('argument must be a array');
}
return new Promise((resolve, reject) => {
let promiseCount = 0;
let promiseNum = promises.length;
let result = [];
for (let i = 0; i < promiseNum; i++) {
Promise.resolve(promises[i])
.then(res => {
promiseCount++;
result[i] = res;
if (promiseCount === promiseNum) {
return resolve(result);
}
})
.catch(e => {
reject(e);
});
}
});
}
Promise.all = function (promiseArr) {
if (!Array.isArray(promiseArr)) {
throw new TypeError('not array');
}
return new Promise((resolve, reject) => {
let i = 0;
let result = [];
let len = promiseArr.length;
let count = len;
function resolver(index) {
return function (value) {
resolveAll(index, value);
}
}
function rejecter(reason) {
reject(reason);
}
function resolveAll(index, value) {
result[index] = value;
if (--count === 0) {
resolve(result);
}
}
for (; i < len; i++) {
promiseArr[i].then(resolver(i), rejecter);
}
})
}
function PromiseAll(promises) {
return new Promise((resolve, reject) => {
let resultCount = 0
let promiseLen = Promise.length // 传入的promise个数
let results = new Array(promiseLen) // 存放返回结果
for (let i = 0; i < promiseLen; i++) {
promises[i].then(value => {
resultCount++;
results[i] = value
if (resultCount === promiseLen) {
return resolve(results)
}
}, error => {
reject(error)
})
}
})
}
function promiseAll(promises) {
if (promises == null) {
throw new TypeError('cannot read Symbol.iterator of undefined')
}
let res = []
let index = 0
return new Promise((resolve, reject) => {
if (promises.length == 0) {
resolve([])
}
for (let i = 0; i < promises.length; i++) {
let p = null
//原始值
if (isOriginValue(promises[i])) {
p = handleOriginValue(promises[i])
} else {
//promise
p = promises[i]
}
p
.then(value => {
res.push(value)
if (++index == promises.length) {
resolve(res)
}
})
.catch(value => {
reject(value)
})
}
});
}
function isOriginValue(originValue) {
return !/Promise]$/.test(Object.prototype.toString.call(originValue))
}
function handleOriginValue(originValue) {
return Promise.resolve(originValue)
}
///////////测试
promiseAll([
Promise.resolve(),
3,
4,
Promise.resolve(3),
Promise.reject(2),
// Promise.reject(6),
Promise.resolve(4)
])
.then(res => console.log('resolve', res))
.catch(rej => console.log('reject', rej)) //reject 2
let p = promiseAll([
Promise.resolve(),
new Promise((resolve, reject) => setTimeout(resolve, 1000))
]);
setTimeout(console.log, 0, p); // Promise <pending>
p.then(() => setTimeout(console.log, 0, 'all() resolved!'));
promiseAll([])
.then(res => console.log('resolve', res)) // []
.catch(rej => console.log('reject', rej))
js
class allReduce {
constructor(){
this.index=0;
}
reduceTime(arr){
const _self=this;
return setTimeout(function(){
_self.all(arr)
},0)
}
all(val){
const _self=this;
if(!Array.isArray(val)) {
throw new Error('参数必须是数组');
return
}
if(val.length==this.index) {
console.log('结束');
return
}
try{
val[_self.index]();
_self.reduceTime(val)
}catch(e){
_self.reduceTime(val)
}
this.index++;
}
}
let promis=new allReduce();
promis.all([function(){console.log(ss)}, async function(){ let n = await 10; console.log("11 ",n)},function(){console.log("22")},async function(){ let n = await 10; console.log("33 ",n),function(){console.log("44")}}])
// 请实现 Promise.all
Promise.all2 = function (promises) {
if (!Array.isArray(promises)) {
throw new Error('all 中必须是数组')
}
return new Promise((resolve, reject) => {
let resolvedCount = 0;
const resolvedValues = new Array(promises.length)
const promisesNum = promises.length
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(res => {
resolvedCount++;
resolvedValues[i] = res
if (resolvedCount === promisesNum) {
resolve(resolvedValues)
}
}, reason => {
reject(reason)
})
}
})
}
function timer(time, val) {
return new Promise((resolve, reject) => {
console.time(val)
setTimeout(() => {
console.timeEnd(val)
resolve(val)
}, time);
})
}
var promises = [
timer(1200, 'xiaoming'),
timer(3000, 'xiaohong'),
timer(2000, 'xiaohuang'),
timer(1500, 'xiaosan'),
3]
console.time('all')
Promise.all2(promises).then(arr => {
console.timeEnd('all')
console.log(arr)
})
// xiaoming: 1202.260986328125 ms
// xiaosan: 1501.62109375 ms
// xiaohuang: 2008.06005859375 ms
// xiaohong: 3000.2119140625 ms
// all: 3001.406982421875 ms
// ["xiaoming", "xiaohong", "xiaohuang", "xiaosan", 3]