promise和await async进阶
写博客,既能梳理了专题知识,又加深记忆和理解,好了,不废话,正文马上开始。
1. promise作用
作用:promise解决回调地狱的问题
2.promise基本用法
一定要记得 new Promise(executor) 的 executor 是马上执行的;
promise、then、finally都是微任务;
let myPromise = new promise(function(resolved,rejected){})
Promise结合setTimeout
微任务包括:MutationObserver、Promise.then()或catch()、Promise为基础开发的其它技术,比如fetch API、V8的垃圾回收过程、Node独有的process.nextTick。
宏任务包括:script 、setTimeout、setInterval 、setImmediate 、I/O 、UI rendering。
event loop它的执行顺序:
- 一开始整个脚本作为一个宏任务执行
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
- 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
- 执行浏览器UI线程的渲染工作
- 检查是否有Web Worker任务,有则执行
- 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
按照event loop规则就能很快输出结果
Promise中的then、catch、finally
- Promise的状态一经改变就不能再改变;
- .then和.catch都会返回一个新的Promise;
- catch不管被连接到哪里,都能捕获上层未捕捉过的错误;
- 在Promise中,返回任意一个非 promise 的值都会被包裹成; promise对象,例如return 2会被包装为return Promise.resolve(2);
async function async1 () {
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
'srcipt start'
'srcipt end'
'async1 end'
复制代码
- Promise 的 .then 或者.catch可以被调用多次,但如果Promise内部的状态一经改变,并且有了一个值,那么后续每次调用.then或者.catch的时候都会直接拿到该值;
- .then 或者 .catch 中 return 一个 error; 对象并不会抛出错误,所以不会被后续的 .catch 捕获;
- .then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环;
- .then 或者 .catch 的参数期望是函数,传入非函数则会发生值透传;
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)
//1 因为发生了透传
复制代码
- .then方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,再某些时候你可以认为catch是.then第二个参数的简便写法;
.finally方法也是返回一个Promise
,他在Promise结束的时候,无论结果为resolved还是rejected,都会执行里面的回调函数。
就像是这里的finally()会等promise1().then()执行完才会将finally()加入微任务队列
其实你只要记住它三个很重要的知识点就可以了:
- .finally()方法不管Promise对象最后的状态如何都会执行
- .finally()方法的回调函数不接受任何的参数,也就是说你在.finally()函数中是没法知道Promise最终的状态是resolved还是rejected的
它最终返回的默认会是一个上一次的Promise对象值
,不过如果抛出的是一个异常则返回异常的Promise对象。
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve('resolve3');
console.log('timer1')
}, 0)
resolve('resovle1');
resolve('resolve2');
}).then(res => {
console.log(res)
setTimeout(() => {
console.log(p1)
}, 1000)
}).finally(res => {
console.log('finally', res)
})
'resolve1'
'finally' undefined
'timer1'
Promise{<resolved>: undefined}
分析:
- Promise的状态一旦改变就无法改变
- finally不管Promise的状态是resolved还是rejected都会执行,且它的回调函数是接收不到Promise的结果的,所以finally()中的res是一个迷惑项(类似3.10)。
- 最后一个定时器打印出的p1其实是.finally的返回值,我们知道.finally的返回值如果在没有抛出错误的情况下默认会是上一个Promise的返回值,
- 而这道题中.finally上一个Promise是.then(),但是这个.then()并没有返回值,所以p1打印出来的Promise的值会是undefined,如果你在定时器的下面加上一个return 1,返回是1。
复制代码
Promise中的all、race
- Promise.all()的作用是
接收一组异步任务
,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。 - .race()的作用也是接收一组异步任务,然后并行执行异步任务,只保留取
第一个执行完成的异步操作
的结果,其他的方法仍在执行,不过执行结果会被抛弃。 - Promise.all().then()结果中数组的顺序和Promise.all()接收到的数组顺序一致。
- all和race传入的数组中如果有会抛出异常的异步任务,那么
只有最先抛出的错误会被捕获
,并且是被then的第二个参数或者后面的catch捕获
;但并不会影响数组中其它的异步任务的执行。
3. await async
正常情况下,async中的await命令是一个Promise对象,返回该对象的结果。
但如果不是Promise对象的话,就会直接返回对应的值,相当于Promise.resolve()
async function fn () {
// return await 123
// 等同于
return 123
}
fn().then(res => console.log(res)) //123
复制代码
async function async1 () {
console.log('async1 start');
await new Promise(resolve => {
console.log('promise1')
})
console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,
因此相当于一直在await,await,await却始终没有响应...,
所以在await之后的内容是不会执行的,也包括async1后面的 .then。
'script start'
'async1 start'
'promise1'
'script end'
复制代码
注意
async function async1 () {
await new Promise(resolve => {
console.log('promise1')
resolve('promise resolve')
})
console.log('async1 success');
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => {
console.log(res)
})
这道过有一点需要注意的,在async1中的newPromise它的resovle的值和async1().then()里的值是没有关系的,小伙伴可能看到resovle('promise resolve')就会误以为是async1().then()中的返回值。
'script start'
'promise1'
'async1 success'
'async1 end' //此处是返回值,不是resovle('promise resolve')
复制代码
await 的异常处理
如果在async函数中抛出了错误,则终止错误结果,不会继续向下执行。
以下例子使用reject和Error,都中断执行
async function async1 () {
await async2();
console.log('async1');
return 'async1 success'
}
async function async2 () {
return new Promise((resolve, reject) => {
console.log('async2')
reject('error')
})
}
async1().then(res => console.log(res))
'async2'
Uncaught (in promise) error
复制代码
改为throw new Error
async function async1 () {
console.log('async1');
throw new Error('error!!!')
return 'async1 success'
}
async1().then(res => console.log(res))
复制代码
如果想要使得错误的地方不影响async函数后续的执行的话:
可以使用try catch
- 可以直接在Promise.reject后面跟着一个catch()方法:
async function async1 () {
// try {
// await Promise.reject('error!!!')
// } catch(e) {
// console.log(e)
// } //此方法也行
await Promise.reject('error!!!')
.catch(e => console.log(e))
console.log('async1');
return Promise.resolve('async1 success')
}
async1().then(res => console.log(res))
console.log('script start')
'script start'
'error!!!'
'async1'
'async1 success'
此处注意catch执行在console.log('async1')之前,不像then的执行顺序
复制代码
await用法的缺点和优点
优点:
- 同步代码思想
- 写法上简单
缺点:
- 有些执行没必要等待
4. Promise和await async
- Promise结合await async
记住紧跟着await后面的语句相当于放在了new Promise中,下一行及之后的语句相当于放在于Promise.then中
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
async1();
console.log('start')
复制代码
- Promise和await async的区别
Promise不会阻塞后面同步代码的执行,await会阻塞
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
setTimeout(() => {
console.log('timer')
}, 0)
console.log("async2");
}
async1();
console.log("start")
执行结果
'async1 start'
'async2'
'start'
'async1 end'
'timer'
定时器始终还是最后执行的,它被放到下一条宏任务的延迟队列中。
复制代码
5. promise手写代码
- v1.0 初始版本myPromise
function myPromise(contructor){
let self = this
self.status = "pending";
self.value = undefinded;
self.reason = undefinded;
function resolved(value){
if(self.status === 'pending'){
self.status = 'resolved';
self.value = value;
}
}
function rejected(){
if(self.status === 'pending'){
self.status = 'rejected';
self.reason = reason;
}
}
contructor(resolved,rejected)
}
myPromise.prototype.then = function(onFullFilled,onRejected){
let self = this;
switch(this.status){
case 'resolved':
onFullFilled(self.value)
case 'rejected':
onRejected(self.value)
}
}
复制代码
- v2.0 基于观察者模式实现
用2个数组onFullfilledArray和onRejectedArray来保存异步的方法。在状态发生改变时,一次遍历执行数组中的方法。
function myPromise(contructor){
let self = this
self.status = "pending";
self.value = undefinded;
self.reason = undefinded;
self.onFullfilledArray = [];
self.onRejectedArray = [];
function resolved(value){
if(self.status === 'pending'){
self.status = 'resolved';
self.onFullfilledArray.forEach(function(f){
f(self.value)
//如果状态从pending变为resolved,那么就遍历执行里面的异步方法
})
}
}
function rejected(){
if(self.status === 'pending'){
self.status = 'rejected';
self.onRejectedArray.forEach(function(f){
f(self.reason)
//如果状态从pending变为rejected,那么就遍历执行里面的异步方法
})
}
}
contructor(resolved,rejected)
}
myPromise.prototype.then = function(onFullFilled,onRejected){
let self = this;
switch(this.status){
case 'pending':
self.onFullfilledArray.push(function(){
onFullFilled(self.value)
}
self.onRejectedArray.push(function(){
onFullFilled(self.reason)
}
case 'resolved':
onFullFilled(self.value)
break;
case 'rejected':
onRejected(self.reason)
break;
default;
}
}
复制代码
通过两个数组,在状态发生改变之后再开始执行,这样可以处理异步resolve无法调用的问题。这个版本的myPromise就能处理所有的异步,那么这样做就完整了吗?
- v3.0 then方法实现链式调用
myPromise.prototype.then = function(onFullFilled,onRejected){
let self = this;
let newPromise;
switch(this.status){
case 'pending':
<!--then返回promise-->
return newPromise = new myPromise(function(resolved,rejected){
self.onFullfilledArray.push(function(){
try{
let temple=onFullfilled(self.value); //得到resolved的值
resolve(temple)
}catch(e){
reject(e) //error catch
}
});
self.onFullfilledArray.push(function(){
try{
let temple=onRejected(self.reason); //得到rejected的值
reject(temple)
}catch(e){
reject(e) //error catch
}
});
})
case 'resolved':
return newPromise = new myPromise(function(resolve,reject){
try{
let temple=onFullfilled(self.value);
//将上次一then里面的方法传递进下一个Promise的状态
resolve(temple);
}catch(e){
reject(e);//error catch
}
})
break;
case 'rejected':
return newPromise = new myPromise(function(resolve,reject){
try{
let temple=onRejected(self.reason);
//将then里面的方法传递到下一个Promise的状态里
resolve(temple);
}catch(e){
reject(e);
}
})
break;
default;
}
}
复制代码
这样通过then方法返回一个promise就可以实现链式的调用:
p.then(function(x){
console.log(x)
})
.then(function(){
console.log("链式调用1")
})
.then(function(){
console.log("链式调用2")
})
//输出
1
链式调用1
链式调用2
复制代码
这样我们虽然实现了then函数的链式调用,但是还有一个问题,就是在Promise/A+规范中then函数里面的onFullfilled方法和onRejected方法的返回值可以是对象,函数,甚至是另一个promise
。 疑问:以上onFullfilled方法和onRejected方法有返回值吗?
4.v4.0 then函数中的onFullfilled和onRejected方法的返回值问题
function resolvePromise(promise,x,resolve,reject){
if(promise===x){
throw new TypeError("type error")
}
let isUsed;
if(x!==null&&(typeof x==="object"||typeof x==="function")){
try{
let then=x.then;
if(typeof then==="function"){
//是一个promise的情况
then.call(x,function(y){
if(isUsed)return;
isUsed=true;
resolvePromise(promise,y,resolve,reject);
},function(e){
if(isUsed)return;
isUsed=true;
reject(e);
})
}else{
//仅仅是一个函数或者是对象
resolve(x)
}
}catch(e){
if(isUsed)return;
isUsed=true;
reject(e);
}
}else{
//返回的基本类型,直接resolve
resolve(x)
}
}
复制代码
改变了resolvePromise函数之后,我们在then方法里面的调用也变成了resolvePromise而不是promise。
myPromise.prototype.then=function(onFullfilled,onRejected){
let self=this;
let promise2;
switch(self.status){
case "pending":
promise2=new myPromise(function(resolve,reject){
self.onFullfilledArray.push(function(){
setTimeout(function(){
try{
let temple=onFullfilled(self.value);
resolvePromise(temple)
}catch(e){
reject(e) //error catch
}
})
});
self.onRejectedArray.push(function(){
setTimeout(function(){
try{
let temple=onRejected(self.reason);
resolvePromise(temple)
}catch(e){
reject(e)// error catch
}
})
});
})
case "resolved":
promise2=new myPromise(function(resolve,reject){
setTimeout(function(){
try{
let temple=onFullfilled(self.value);
//将上次一then里面的方法传递进下一个Promise状态
resolvePromise(temple);
}catch(e){
reject(e);//error catch
}
})
})
break;
case "rejected":
promise2=new myPromise(function(resolve,reject){
setTimeout(function(){
try{
let temple=onRejected(self.reason);
//将then里面的方法传递到下一个Promise的状态里
resolvePromise(temple);
}catch(e){
reject(e);
}
})
})
break;
default:
}
return promise2;
}
复制代码
6. 如何让异步顺序执行
var arr = [1, 2, 3, 4]
var promises = []
arr.map(async (value) => {
promises.push(new Promise((res) => {
setTimeout(() => {
console.log(value)
res()
}, 1000)
}))
})
var promise = Promise.resolve()
for (var i = 0; i < promises.length; i += 1) {
const task = promises[i];
promise.then(() => {
return task
})
}
复制代码
arr.reduce((p, x) => p.then(() => new Promise(r => setTimeout(() => r(console.log(x)), 1000))), Promise.resolve())
复制代码
const arr = [1, 2, 3]
arr.reduce((p, x) => {
return p.then(() => {
return new Promise(r => {
setTimeout(() => r(console.log(x)), 1000)
})
})
}, Promise.resolve())
复制代码
注意掌握reduce的高级用法,此处我还得多写几个例子加深理解
7. 场景题目
使用Promise实现每隔1秒输出1,2,3
做此题先写循环方法代码,不能满足要求
function print(){
for (let i=1;i<4;i++){
console.log('first:',i)
new Promise(()=>{
console.log('second:',i)
setTimeout(function(){
console.log(i++)
},1000)
})
}
}
print()
async function print(){
let a = [1,2,3]
for (let i of a){
console.log('first',i)
await new Promise((resolved)=>{
resolved(i)
}).then(()=>{
console.log('second:',i)
setTimeout(function(){
console.log(i)
},1000)})
}
}
print()
//都是先输出
> "first" 1
> "second:" 1
> "first" 2
> "second:" 2
> "first" 3
> "second:" 3
再1s后同时并行输出
> 1
> 2
> 3
原因:在一个循环作用域下,执行异步
new Promise是微任务,setTimeout是宏任务
主程序完成之后,执行微任务,宏任务压入执行队列中
复制代码
async function print(){
let a = [1,2,3]
for (let i of a){
console.log('first',i)
await new Promise((resolved)=>{
resolved(i)
}).then(()=>{
console.log('second:',i)
// setTimeout(function(){
console.log(i)
// },1000)
})
}
}
> "first" 1
> "second:" 1
> 1
> "first" 2
> "second:" 2
> 2
> "first" 3
> "second:" 3
> 3
复制代码
function print(i){
return new Promise((resolved)=>{
setTimeout(function(){
console.log(i)
resolved(i)
},2000)
})
}
print(1).then(()=>{
print(2)
}).then(()=>{
print(3)
})
2s后先出现1,再出现2,3,因为setTimeout最后面执行
> 1
> 2
> 3
复制代码
function print(i){
return new Promise((resolved)=>{
setTimeout(function(){
console.log(i)
resolved(i)
},2000)
})
}
async function a(i){
await print(i)
}
a(1)
a(2)
a(3)
2s后同时出现
> 1
> 2
> 3
复制代码
var arr = [1, 2, 3, 4]
var promises = []
arr.map(async (value) => {
promises.push(new Promise((res) => {
setTimeout(() => {
console.log(value)
res()
}, 2000)
}))
})
var promise = Promise.resolve()
for (var i = 0; i < promises.length; i += 1) {
const task = promises[i]
promise
.then(() => {
return task
})
}
2s后同时出现
> 1
> 2
> 3
> 4
复制代码
把let改成var
function print(){
for (var i=1;i<4;i++){
console.log('first:',i)
new Promise(()=>{
console.log('second:',i)
setTimeout(function(){
console.log(i++)
},1000)
})
}
}
print()
//先输出
> "first" 1
> "second:" 1
> "first" 2
> "second:" 2
> "first" 3
> "second:" 3
再1s后同时并行输出
> 4
> 5
> 6
因为先执行了for循环,再执行new Promise
当异步事件发生时,会创建事件并放入执行队列中,等待当前代码执行完成之后再执行这些代码。
复制代码
如何让异步操作顺序执行 最终代码:
const arr = [1, 2, 3]
arr.reduce((p, x) => {
return p.then(() => {
return new Promise(r => {
setTimeout(() => r(console.log(x)), 1000)
})
})
}, Promise.resolve())
部分变成非箭头函数
const arr = [1, 2, 3]
arr.reduce((p, x) => {
return p.then(() => {
return new Promise(function(resolved){
setTimeout(function(){
resolved(console.log(x))
//console.log(x) 如果没有resolved()包含console.log(x),则仅仅1s后输出1
}, 1000)
})
})
}, Promise.resolve())
要知道resolved是个函数
每隔1s后输出
> 1
> 2
> 3
复制代码
红灯3秒亮一次,黄灯2秒亮一次,绿灯1秒亮一次,使用Promise实现红绿灯交替重复亮?
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
new Promise((resolve)=>{
setTimeout(()=>{
red()
resolve()
},3000)
}).then((resolve) => {
setTimeout(()=>{
green()
//resolve()
},2000)
}).then((resolve) => {
setTimeout(()=>{
yellow()
// resolve()
},1000)
})
> "red"
> "yellow"
> "green"
报错:VM5613:22 Uncaught TypeError: resolve is not a function
要知道then后面没有resolved函数
复制代码
下面换return方式试:
function print(timer,cb){
return new Promise(function(resolve){
setTimeout(() => {
cb()
resolve()
}, timer)
})
}
Promise.resolve().then(() => {
return print(3000, red)
}).then(() => {
return print(2000, green)
}).then(() => {
return print(1000, yellow)
})
3s后输出"red",2s后输出"green",1s后输出"yellow"
> "red"
> "green"
> "yellow"
我自己的解释:Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象,所以回调函数会立即执行;then()函数里不返回值或者返回的不是promise,那么 then 返回的 Promise 将会成为接受状态(resolve)
`都是在then之后返回print,也就是new Promise`
new Promise(()=>{
return print(3000, red)
}).then(() => {
return print(2000, green)
}).then(() => {
return print(1000, yellow)
})
3s后输出
> "red"
new Promise((resolve)=>{
//return new Promise(function(resolve){
setTimeout(() => {
red()
resolve()
}, 3000)
//})
}).then(() => {
return new Promise(function(resolve){
setTimeout(() => {
green()
resolve()
}, 2000)
})
}).then(() => {
return new Promise(function(resolve){
setTimeout(() => {
yellow()
resolve()
}, 2000)
})
})
注释then之前的return,为了获取resolve状态,这个很能对比Promise.resolve()
> 3s后输出"red",2s后输出"green",1s后输出"yellow"
复制代码
这个想象让我问自己为什么第一行必须写Promise.resolve()
来了解下new Promise()和Promise.resolve()的区别
Promise.resolve()
1)如果参数是一个Promise实例,Promise.resolve将不做任何修改、原封不动地返回这个实例
let v = new Promise(resolve => {
console.log("begin");
//resolve("then");
});
Promise.resolve(v)
> "begin"
let v = new Promise(resolve => {
console.log("begin");
resolve("then");
});
Promise.resolve(v).then((res)=>console.log(res))
> "begin"
> "then"
复制代码
2)如果参数是一个包含then的对象
Promise.resolve方法会将这个对象转为 Promise 对象实例
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
}
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
复制代码
3)参数不是具有then方法的对象,或根本就不是对象,也不是Promise实例
Promise.resolve方法返回一个新的 Promise 对象,状态为resolved
const p = Promise.resolve('HHY');
console.log(p) //Promise {<resolved>: "HHY"}
p.then(function (s){
console.log(s)
});
> HHY
复制代码
4)不带任何参数
直接返回一个resolved状态的 Promise 对象
console.log(Promise.resolve()) //Promise {<resolved>: undefined}
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
> "one"
> "two"
> "three"
复制代码
.then()函数里不返回值或者返回的不是promise
,那么 then 返回的 Promise 将会成为接受状态(resolve)
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3)
);
console.log(1);
> 1
> 2
> 3
复制代码
先输出1的原因:
Promise.resolve(),是在本轮“事件循环”(event loop)的结束时执行
,不是马上执行,也不是在下一轮“事件循环”的开始时执行.
原因:传递到 then() 中的函数被置入了一个微任务队列
,而不是立即执行,这意味着它是在 JS 事件队列的所有运行时结束了,事件队列(我的理解是同步代码的事件队列)被清空之后
,才开始执行.
new Promise()
let v = new Promise(resolve => {
console.log("begin");
resolve("then");
});
复制代码
在promise里面resolve一个状态为fulfilled的promise
resolve()本质作用:
resolve()是用来表示promise的状态为fullfilled,相当于只是定义了一个有状态的Promise,但是并没有调用它; promise调用then的前提是promise的状态为fullfilled; 只有promise调用then的时候,then里面的函数才会被推入微任务中;
区别
- new promise是返回一个promise对象
- Promise.resolve() 返回一个promise对象,状态为resolved
- Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象,所以回调函数会立即执行;then()函数里不返回值或者返回的不是promise,那么 then 返回的 Promise 将会成为接受状态(resolve)
因此new promise的操作就跟你 new 一个普通函数没区别,所以这一句其实是宏任务,但后面的then是微任务
resolved后的promise对象会在这该级别事件队列结束之后才开始执行,及执行与该轮微任务队列中,始于下一级别宏任务之前
Promise.resolve()可以返回实例对象。
Promise.resolve(v)不等于new Promise(r => r(v))
当v是一个Promise实例的时候就会出现一些不同的地方
// v是一个实例化的promise,且状态为fulfilled
let v = new Promise(resolve => {
console.log("begin");
resolve("then");
});
模式一 new Promise里的resolve()
结果: begin->1->2->3->then->4 可以发现then推迟了两个时序
推迟原因:浏览器会创建一个 PromiseResolveThenableJob 去处理这个 Promise 实例,这是一个微任务。
等到下次循环到来这个微任务会执行,也就是PromiseResolveThenableJob 执行中的时候,因为这个Promise 实例是fulfilled状态,所以又会注册一个它的.then()回调
又等一次循环到这个Promise 实例它的.then()回调执行后,
才会注册下面的这个.then(),于是就被推迟了两个时序
new Promise(resolve => {
console.log(v) //Promise {<resolved>: "then"}
console.log(resolve(v)) //undefined
resolve(v);
}).then((v)=>{
console.log(v) //获取then值得地方
}); //begin->1->2->3->then->4
我的理解:resolve中包含实例对象,先输出begin,再执行下面输出1,2,3(1理解,为什么会执行了2和3,再then呢?),再来执行获取then值得地方
模式二 Promise.resolve(v)直接创建
结果:begin->1->then->2->3->4 可以发现then的执行时间正常了,第一个执行的微任务就是下面这个.then
原因:Promise.resolve()API如果参数是promise会直接返回这个promise实例,不会做任何处理
Promise.resolve(v).then((v)=>{
console.log(v)
}); //begin->1->then->2->3->4
new Promise(resolve => {
console.log(1);
resolve();
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(4);
});
> "begin"
> 1
> "then"
> 2
> 3
> 4
> "begin"
> 1
> 2
> 3
> "then"
> 4
复制代码
实现mergePromise函数
把传进去的数组按顺序先后执行,并且把返回的数据先后放到数组data中。
const time = (timer) => {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, timer)
})
}
const ajax1 = () => time(2000).then(() => {
console.log(1);
return 1
})
const ajax2 = () => time(1000).then(() => {
console.log(2);
return 2
})
const ajax3 = () => time(1000).then(() => {
console.log(3);
return 3
})
function mergePromise (ajaxArray) {
// 存放每个ajax的结果
const data = [];
let promise = Promise.resolve();
ajaxArray.forEach(ajax => {
// 第一次的then为了用来调用ajax
// 第二次的then是为了获取ajax的结果
promise = promise.then(ajax).then(res => {
data.push(res);
return data; // 把每次的结果返回
})
})
// 最后得到的promise它的值就是data
return promise;
}
mergePromise([ajax1, ajax2, ajax3]).then(data => {
console.log("done");
console.log(data); // data 为 [1, 2, 3]
});
复制代码
根据promiseA+实现一个自己的promise
封装一个异步加载图片的方法
,只需要在图片的onload函数中,使用resolve返回一下就可以了。
function loadImg(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = function() {
console.log("一张图片加载完成");
resolve(img);
};
img.onerror = function() {
reject(new Error('Could not load image at' + url));
};
img.src = url;
});
复制代码
限制异步操作的并发个数并尽可能快的完成全部
8. 参考链接
9. 后语
花了一周时间整理,一些标记是自己不熟悉的地方,另外一些升华题需要继续研究,有时间继续补充和更正,请大家阅读,有收获请给个👍