promise
- 异步编程解决方案,回调地狱
- 三个状态
pending
fulfilled
rejected - promise
promise当状态改变,就会触发then里面的响应函数处理后续步骤, 只有promise调用then的时候,then里面的函数才会被推入微任务中
var promise = new Promise(function(reslove, reject) {
if(异步操作成功) {
reslove(value);
}else {
reject(error);
}
})
- 状态改变(且状态改变之后就不会再改变了)
pending -> fulfilled
pending -> rejected
var promise = new Promise((reslove, reject) => {
reject("error");
})
var a = promise.then(res => {
console.log(res);
}, error => {
console.log("reject error", error)
}).catch(err => {
console.log("catch error", err);
});
console.log(a); // Promise {pending}
只有promise调用then的时候,then里面的函数才会被推入微任务中
new Promise(resolve => {
console.log(1); // 1
resolve(3);
Promise.resolve().then(()=> console.log(4)) // 3
}).then(num => {
console.log(num); // 4
setTimeout(()=>{console.log(6)},0); // 5
});
console.log(2); // 2
promise.all
promise.all可以将多个Promise实例包装成一个新的Promise实例。
同时,成功和失败的返回值是不同的
成功的时候返回的是一个结果数组,
失败的时候返回最先被reject失败状态的值
let p1 = new Promise((reslove, reject) => {
reslove("success 1")
})
let p2 = new Promise((reslove, reject) => {
reslove("success 2")
})
let p3 = Promise.reject("failed")
Promise.all([p1,p2]).then(result => {
console.log(result); // ["success 1", "success 2"]
}, err => {
console.log("reject",err);
})
Promise.all([p1,p2,p3]).then(result => {
console.log(result);
}, err => {
console.log("err", err); // err failed
})
promise.race (赛跑)
promise.race([p1,p2,p3])里面哪个结果获得的块,就返回哪个结果
不管结果本身是成功状态还是失败状态
let p4 = new Promise((reslove, reject) => {
setTimeout(() => {
reslove("sucess")
}, 1000)
})
let p5 = new Promise((reslove, reject) => {
setTimeout(() => {
reject("failed")
}, 500)
})
Promise.race([p4,p5]).then(result => {
console.log(result);
}, err => {
console.log(err); // failed
})
1. Promise.reslove()
2. Promise.reject()
3. Promise.prototype.finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
finally方法的回调函数不接受任何参数,表明finally里面的操作与状态无关
finally方法总是会返回原来的值
实现finally
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})
// resolve 的值是 2
Promise.resolve(2).finally(() => {})
// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})
// reject 的值是 3
Promise.reject(3).finally(() => {})
4. Promise.try()
不知道或者不想区分,函数f是同步函数还是异步操作,但是想用 Promise 来处理它。因为这样就可以不管f是否包含异步操作,都用then方法指定下一步流程,用catch方法处理f抛出的错误。
5. Promise.allSettled()
等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作
Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。
只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。
一旦发生状态变更,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,它的回调函数会接收到一个数组作为参数,该数组的每个成员对应前面数组的每个 Promise 对象。
results的每个成员是一个对象,对象的格式是固定的,对应异步操作的结果。
成员对象的status属性的值只可能是字符串fulfilled或字符串rejected,用来区分异步操作是成功还是失败。如果是成功(fulfilled),对象会有value属性,如果是失败(rejected),会有reason属性,对应两种状态时前面异步操作的返回值。
// 异步操作成功时
{status: 'fulfilled', value: value}
// 异步操作失败时
{status: 'rejected', reason: reason}
6. Promise.any()
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()抛出的错误,不是一个一般的 Error 错误对象,而是一个 AggregateError 实例。它相当于一个数组,每个成员对应一个被rejected的操作所抛出的错误。
Promise.done
Promise 对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。
实现:
promise.prototype.done = function() {
this.catch(reason => {
throw reason
})
}
// 或者
promise.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected)
.catch(function (reason) {
throw reason
});
};
可以像then方法那样用,提供fulfilled和rejected状态的回调函数,也可以不提供任何参数。但不管怎样,done都会捕捉到任何可能出现的错误,并向全局抛出。
多个promise,依次执行,并返回结果,单例方法避免多次调用
const reqs = new Array(10).fill(false).map((_, i) =>
() => new Promise(resolve => setTimeout(() => { console.log(i); resolve(i) }, 1000)))
// 要求:实现executeSerial函数,功能如下:接受一个数组,数组的每一项是一个返回promise的函数,要在第一个函数返回的promise resolve后,再执行第二个。
const executeSerial = (reqs) => {
reqs = Array.isArray(reqs) ? reqs : [reqs];
// p.then() -> p1.then() -> p2.then()
// return function (props) {
return reqs.reduce((pre, next, index, arr) => {
return pre.then(() => {
return next()
})
}, Promise.resolve()
)
// }
}
executeSerial(reqs)
singleFn = function ( app ) {
if ( app.loadingPromiese ) {
return app.loadingPromiese
}
return (
app.loadingPromiese = Promise.resolve().then(
() => {
console.log( 'do some thing' )
delete app.loadingPromiese
return app
}
)
)
}
// 避免方法多次调用技巧
async await
- await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果;
如果不是 promise , 把这个直接量,作为 await表达式的结果。 - 特别注意:如果promise没有一个成功的值传入,对await来说就算是失败了,下面的代码就不会执行。
代码从右向左执行,先执行右侧的代码,执行完后,发现有await关键字,于是让出线程,阻塞代码,如果await的结果是reject,后面的代码就不会执行了,加try, catch
async function f() {
return "abc"// 将abc 自动包装成promise对象 Promise.reslove('abc')
}
console.log(f()) // promise对象
function fn(){
return new Promise(resolve=>{
console.log(1)
// resolve();
})
}
async function f1(){
await fn()
console.log(2)
}
f1()
console.log(3)
// 1 3
// 1 3 2
- 异步操作解决方案
回调函数-> promise对象-> generator函数->async await - async函数就是Generator函数的语法糖
- async函数优点
内置执行器【Generator函数执行必须靠执行器】
更广的适用性【co函数库约定,yield命令后只能是Thunk函数或Promise对象;await后面可以跟Promise对象和原始类型的值】 - async函数的实现
将Generator函数和自动执行器,包装再一个函数里
async function fn(args){
// ...
}
// 等同于
function fn(args){
// spawn 函数就是自动执行器
return spawn(function*() {
// ...
});
}
经典面试题
async function async1() {
console.log('async1 start') // 2
await async2() // 执行完await 让出线程
console.log('async1 end') // 6
}
async function async2() {
console.log('async2') // 3
}
console.log('script start') // 1
setTimeout(function () {
console.log('setTimeout') // 8
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1') // 4
resolve();
}).then(function () {
console.log('promise2') // 7
})
console.log('script end') // 5
async function async1() {
console.log('async1 start') // 2
await Promise.resolve().then(() => {
console.log('async2') // 5
})
console.log('async1 end') // 7
}
console.log('script start') // 1
setTimeout(function () {
console.log('setTimeout') // 8
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1') // 3
resolve();
}).then(function () {
console.log('promise2') // 6
})
console.log('script end') // 4
async function async1() {
console.log('async1 start') // 2
await async2() // 执行完await 让出线程
console.log('async1 end') // 6
}
async function async2() {
Promise.resolve().then(() => {
console.log('async2'); // 5
})
}
console.log('script start') // 1
setTimeout(function () {
console.log('setTimeout') // 8
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1') // 3
resolve();
}).then(function () {
console.log('promise2') // 7
})
console.log('script end') // 4
能发现区别是微任务的执行在后面两端2,3中的区别,会执行await后面的微任务,2中两个微任务在同一微任务队列中,后面3中async2微任务和promise.then不在同一个队列中。
本文详细介绍了Promise的使用,包括promise.all、promise.race、resolve、reject、finally、Promise.try、allSettled和any等方法。此外,还讨论了async/await的原理和应用场景,以及经典的面试题和generator函数的相关知识。
953

被折叠的 条评论
为什么被折叠?



