Open YvetteLau opened 5 years ago
Promise.all 接收一个 promise 对象的数组作为参数,当这个数组里的所有 promise 对象全部变为resolve或 有 reject 状态出现的时候,它才会去调用 .then 方法,它们是并发执行的。
实现方法
function promiseAll(promises) {
return new Promise(function(resolve, reject) {
if (!isArray(promises)) {
return reject(new TypeError('arguments must be an array'));
}
var resolvedCounter = 0;
var promiseNum = promises.length;
var resolvedValues = new Array(promiseNum);
for (var i = 0; i < promiseNum; i++) {
(function(i) {
Promise.resolve(promises[i]).then(function(value) {
resolvedCounter++
resolvedValues[i] = value
if (resolvedCounter == promiseNum) {
return resolve(resolvedValues)
}
}, function(reason) {
return reject(reason)
})
})(i)
}
})
}
使用方法
var p1 = Promise.resolve(1),
p2 = Promise.reject(2),
p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
//then方法不会被执行
console.log(results);
}).catch(function (e){
//catch方法将会被执行,输出结果为:2
console.log(2);
});
总结
如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象
如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调
只要有一个失败,状态就变为 rejected,返回值将直接传递给回调 all() 的返回值也是新的 Promise 对象
function promiseAll(promises) {
return new Promise((resolve, reject) => {
let resultCount = 0;
let results = new Array(promises.length);
for (let i = 0; i < promises.length; i++) {
promises[i].then(value => {
resultCount++;
results[i] = value;
if (resultCount === promises.length) {
return resolve(results)
}
}, error => {
reject(error)
})
}
})
}
/**
*实现promise中的all方法
*/
function all(array) {
judgeType(array);
return new Promise((resolve, reject) => {
let count = 0;
array.forEach(element => {
element.then(() => {
count += 1;
if (array.length === count) {
resolve();
}
});
element.catch((error) => {
reject(error);
});
});
});
}
/**
*类型的判断
*/
function judgeType(array) {
if (array instanceof Array) {
array.forEach(item => {
if (!(item instanceof Promise)) {
throw "该参数的每一项必须是Promise的实例";
}
});
} else {
throw "必须是数组哦";
}
}
promise 是对异步编程的一种抽象。它是一个代理对象,代表一个必须进行异步处理的函数返回的值或抛出的异常。
function promiseAll(promises) { return new Promise(function(resolve, reject) { if (!isArray(promises)) { return reject(new TypeError('arguments must be an array')); } var resolvedCounter = 0; var promiseNum = promises.length; var resolvedValues = new Array(promiseNum); for (var i = 0; i < promiseNum; i++) { (function(i) { Promise.resolve(promises[i]).then(function(value) { resolvedCounter++ resolvedValues[i] = value if (resolvedCounter == promiseNum) { return resolve(resolvedValues) } }, function(reason) { return reject(reason) }) })(i) } }) }
Promise.all方法有以下几个特点
Promise.all = function(promises) {
return new Promise(function(resolve, reject) {
if (!promises || typeof promises !== 'object' || typeof promises[Symbol.iterator] !== 'function') {
reject(TypeError());
}
if (promises.length === 0) {
resolve([]);
} else {
let ans = [];
let index = 0;
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function(data) {
// 不能用Push操作,因为不能确定谁先回来,要用index来记录,否则无法准确获得当前收到的结果的数目
index++;
ans[i] = data;
if (index === promises.length) {
resolve(ans);
}
}, function(error) {
reject(error);
});
}
}
});
}
Promise.myAll = function(promises) {
let results = [];
let count = 0;
let len = promises.length;
return new Promise(function(resolve, reject) {
if (!(promises instanceof Array))
return reject("arguments must be an array");
for (let val of promises) {
Promise.resolve(val).then(
function(res) {
count++;
results.push(res);
if (count === len) {
return resolve(results);
}
},
function(err) {
return reject(err);
}
);
}
});
};
Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例
const obj1= Promise.all([p1,p2])
接受一个数组参数 obj1 的状态有两种: 1.当 p1,p2 的状态都是 fulfilled 时,obj1 的状态是 fulfilled 2.p1 , p2只要其中一个的状态是 rejected,obj1 的状态是 rejected
代码:
const p1 = new Promise((resolve,reject)=>{
resolve()
}).then(()=>{
console.log('success1')
}).catch(()=>{
console.log('error1')
})
const p2 = new Promise((resolve,reject)=>{
reject()
}).then(()=>{
console.log('success2')
}).catch(()=>{
console.log('error2')
})
const a = Promise.all([
p1,
p2
]).then(()=>{
console.log('success')
}).catch(()=>{
console.log('error')
})
执行结果 success1 error2 success
为什么p2是rejected状态,但是promise.all的状态却是fulfilled,输出success?因为p2抛出的错误已经在p2里面处理了,倘若p2的错误没有被处理,那么promise.all就会执行catch( )方法。
Promise.all接收一个数组,如果传入数组的每个元素不是promise对象,则将其转换为promise对象。当数组中每个promise的执行结果都变为resolve时,调用then方法的成功回调函数;如果数组中有一个promise对象的执行结果变为reject,则调用then方法的失败回调函数。
Promise.all = (promises) => {
return new Promise(resolve, reject){
if(!isArray(promises)) {
return reject('arguments must be an array.')
}
let len = promises.length;
let count = 0;
let res = [];
for (let i = 0; i< len; i++){
Promise.resolve(promises[i]).then((value) => {
count ++;
res[i] = value;
if (count === len) {
return resolve(res)
}
}, (reason) => {
return reject(reason)
})
}
}
}
思量了半天,原生的Promise 无法一时写出来
这边稍微利用下Promise来实现 Promise.all
Promise.all = arr => {
const results = []
return new Promise(resolve => {
let i =0;
function next () {
arr[i] && arr[i].then(res=>{
result.push(res);
i++;
if (i == arr.length) {
resolve(result)
} esle {
next()
}
})
}
})
}
Promise.all([p1,p2,p3]) 以数组的形式传入每个promise实例,返回一个新的promise对象 每个实例的结果均为resolve时,将结果推入数组中,并resolve出来。 有一个实例的结果为reject时,就reject出来 Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
Promise.all = promises => {
return new Promise((resolve,reject) => {
if(typeof promises[Symbol.iterator] != 'function' ){
reject('类型错误')
}
if(promises.length == 0){
reject([])
}else{
const targetArr = []
const len = promises.length
const index = 0
for(let i = 0;i<len;i++){
//通过Promise.resolve方法得到每个promise实例的结果
Promise.resolve(promises[i]).then(value => {
index++;
targetArr[i] = value
if(index == len){
resolve(targetArr)
}
}).catch(err => {
reject(err)
})
}
}
})
}
在实现 Promise.all 方法之前,我们首先要知道 Promise.all 的功能和特点,因为在清楚了 Promise.all 功能和特点的情况下,我们才能进一步去写实现。
Promise.all(iterable)
返回一个新的 Promise 实例。此实例在 iterable
参数内所有的 promise 都 fulfilled
或者参数中不包含 promise
时,状态变成 fulfilled
;如果参数中 promise
有一个失败rejected
,此实例回调失败,失败原因的是第一个失败 promise 的返回结果。
let p = Promise.all([p1, p2, p3]);
p的状态由 p1,p2,p3决定,分成以下;两种情况:
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.all 的返回值是一个 promise 实例
Promise.all
会 同步 返回一个已完成状态的 promise
Promise.all
会 异步 返回一个已完成状态的 promise
(不包含 promise,意味着不会一直 pending 和 rejected )Promise.all
返回一个 处理中(pending) 状态的 promise
.Promise.all 返回的 promise 的状态
Promise.all
返回的 promise 异步地变为完成。Promise.all
异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成Promise.all
返回的 promise 的完成状态的结果都是一个数组仅考虑传入的参数是数组的情况
/** 仅考虑 promises 传入的是数组的情况时 */
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
if (promises.length === 0) {
resolve([]);
} else {
let result = [];
let index = 0;
for (let i = 0; i < promises.length; i++ ) {
//考虑到 i 可能是 thenable 对象也可能是普通值
Promise.resolve(promises[i]).then(data => {
result[i] = data;
if (++index === promises.length) {
//所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 态
resolve(result);
}
}, err => {
reject(err);
return;
});
}
}
});
}
可使用 MDN 上的代码进行测试
考虑传入的参数是 一个可迭代对象
Promise.all = function (promises) {
/** promises 是一个可迭代对象,省略对参数类型的判断 */
return new Promise((resolve, reject) => {
if (promises.length === 0) {
//如果传入的参数是空的可迭代对象
return resolve([]);
} else {
let result = [];
let index = 0;
let iterator = promises[Symbol.iterator]();
function next() {
try {
var { value, done } = iterator.next();
if(!done) {
Promise.resolve(value).then(data => {
result[index] = data;
index++;
next();
}, err => {
//某个promise失败
reject(err);
return;
});
}else {
//迭代完成
resolve(result);
}
} catch (e) {
return reject(e);
}
}
next(); //执行一次next
}
});
}
测试代码:
let p2 = Promise.all({
a: 1,
[Symbol.iterator]() {
let index = 0;
return {
next() {
index++;
if (index == 1) {
return {
value: new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
}), done: false
}
} else if (index == 2) {
return {
value: new Promise((resolve, reject) => {
resolve(222);
}), done: false
}
} else if(index === 3) {
return {
value: 3, done: false
}
}else {
return { done: true }
}
}
}
}
});
setTimeout(() => {
console.log(p2)
}, 200);
学习promise.all(),要先了解promise的作用和特性。promise是一个对象,Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。 promise.all() promise.all(iterable)方法返回一个promise实例,此实例在iterable参数内所有的promise都完成(resolved)或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。(iterable:一个可迭代对象,如 Array 或 String)
var promise1 = Promise.resolve(3)
var promise2 = 42;
var promise3 = new Promise((resolve,reject)=>{
setTimeout(resolve,1000,'foo')
})
Promise.all([promise1,promise2,promise3]).then((values)=>{
console.log(values) //[3,42,'foo']
})
// 下面的例子中演示了promise,all的异步性 var resolvedPromiseArray = [Promise.resolve(33),Promise.resolve(44)]; var p = Promise.all(resolvedPromiseArray); console.log(p) setTimeout((console.log('Array',p)))
// 但是,Promise.all 当且仅当传入的可迭代对象为空时为同步:
var pt = Promise.all([])
var pt2=Promise.all([1331,'nihzo'])
setTimeout(()=>{
console.log('[]',pt2);
})
'use strict'
const createPromise = (method) => {
const promise = new Promise((resolve, reject) => {
method(resolve, reject)
})
return promise
}
const all = (...tasks) => {
tasks = tasks.flat()
let tasksRunCount = 0
let tasksResList = []
let tasksLength = tasks.length
return createPromise((resolve, reject) => {
for (let step = 0, len = tasksLength; step < len; ++step) {
const task = Promise.resolve(tasks[step])
task.then(taskRes => {
tasksRunCount++
tasksResList[step] = taskRes
if (tasksRunCount === tasksLength) {
resolve(tasksResList)
}
}).catch(tashRej => {
reject(tashRej)
})
}
})
}
const p1 = createPromise((resolve, reject) => {
resolve("p1")
})
const p2 = createPromise((resolve, reject) => {
reject("p2")
})
const p3 = createPromise((resolve, reject) => {
reject("p3")
})
all([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
Promise.all = function (promises) {
return new Promise(((resolve, reject) => {
const result = [];
let count = 0;
function done(i, data) {
result[i] = data;
if (++count === promises.length) { resolve(result); }
}
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then((data) => {
done(i, data);
}, reject);
}
}
));
};
测试代码
let promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, '200');
})
let promise2 = 43
let promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, '100');
});
Promise.all([promise1,promise2, promise3]).then((values) => {
console.log(values); // [200, 43, 100]
}, (err) => {
console.log(err)
});
promise.all传入多个promise对象 返回一个新的promise实例 promise.all返回的结果有如下几种状态 示例代码:
const result = promise.all(p1,p2,p3)
成功状态 当p1 ,p2,p3 都执行完毕之后,且都返回success,那么promise.all,会返回一个数组,分别是三个promise对象的返回结果,状态为fullfilled。
失败状态 当p1,p2,p3 都执行完毕,只要其中任何一个出现错误,那么promise.all会返回一个当前的错误实例,状态为rejected。
实现一个promise.all(般一下大佬的代码):
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
if (promises.length === 0) {
resolve([]);
} else {
let result = [];
let index = 0;
for (let i = 0; i < promises.length; i++ ) {
//考虑到 i 可能是 thenable 对象也可能是普通值
Promise.resolve(promises[i]).then(data => {
result[i] = data;
if (++index === promises.length) {
//所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 态
resolve(result);
}
}, err => {
reject(err);
return;
});
}
}
});
}
function isArray(object){
return object && typeof object==='object' &&
object instanceof Array;
}
Promise.myall = function (promiseList) {
if (!isArray(promiseList)) {
return 'not an array'
}
return new Promise ((resolve, reject)=> {
let count = 0
promiseList.forEach(element => {
element.then(() => {
count ++;
if (promiseList.length === count) {
resolve()
}
}).catch(error =>{
reject(error)
})
})
})
}
var p1 = Promise.resolve(1),
p2 = Promise.reject(2),
p3 = Promise.resolve(3);
Promise.myall([p1, p2, p3]).then(function (results) {
//then方法不会被执行
console.log(results);
}).catch(function (e){
//catch方法将会被执行,输出结果为:2
console.log(2);
});
function runAsync1(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('异步任务1执行完成');
resolve('随便什么数据1');
}, 1000);
});
return p;
}
function runAsync2(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('异步任务2执行完成');
resolve('随便什么数据2');
}, 2000);
});
return p;
}
function runAsync3(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('异步任务3执行完成');
resolve('随便什么数据3');
}, 2000);
});
return p;
}
Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。我们仍旧使用上面定义好的runAsync1、runAsync2、runAsync3这三个函数,看下面的例子
Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
console.log(results);
});
用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。
有了all,你就可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据,是不是很酷?有一个场景是很适合用这个的,一些游戏类的素材比较多的应用,打开网页时,预先加载需要用到的各种资源如图片、flash以及各种静态文件。所有的都加载完后,我们再进行页面的初始化。
Promise.nanlan = function (promises) {
let promiselength = promises.length;
let result = [];
let count =0;
return new Promise(function (resolve, reject) {
if (!(promises instanceof Array)) {
return reject("params muse be Arrary");
}
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then((res) => {
count++;
result[i] = res;
if ( count === promiselength) {
return resolve(result)
}
}, (err) =>{
return reject(err)
})
}
})
}
// 测试代码
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.nanlan([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
Promise.all = async function (promises) {
const res = [];
try {
for await (let p of promises) {
const val = p;
res.push(val);
}
return Promise.resolve(res);
} catch (err) {
return Promise.reject(err);
}
};
Promise.all = Promise.all || function(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject("arguments must be array");
}
if (!promises.length) {
resolve([]);
}
let count = 0;
const values = [];
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(
res => {
count++;
values[i] = res;
if (count === promises.length) {
resolve(values);
}
},
err => {
reject(err);
}
);
}
});
};
无论怎么手动模拟,Promise.all 的并发这个根本 feature 难实现的。 借助 web-worker 算是一条思路。
这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我已经收到了,辛苦你了!
使用async / await写法改写了一下函数实现,更容易理解
function promiseAll(promises) {
let promsieLength = promises.length;
let resolvedLength = 0;
let resolvedResults = [];
return new Promise(async (resolve, reject) => {
for(let i = 0; i < promsieLength; i++) {
let result = await promises[i];
resolvedLength++;
resolvedResults.push(result);
if(resolvedLength === promsieLength) {
resolve(resolvedResults)
}
}
})
}
// 测试用例
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3)
}, 2000)
})
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
})
promiseAll([p1, p2, p3]).then(res => {
console.log(res)
})
这是来自QQ邮箱的假期自动回复邮件。你好,你的邮件我已经收到了,辛苦你了!