promise,async await, generator函数

本文详细介绍了Promise的使用,包括promise.all、promise.race、resolve、reject、finally、Promise.try、allSettled和any等方法。此外,还讨论了async/await的原理和应用场景,以及经典的面试题和generator函数的相关知识。

promise

Promise

  1. 异步编程解决方案,回调地狱
  2. 三个状态
    pending
    fulfilled
    rejected
  3. promise
    promise当状态改变,就会触发then里面的响应函数处理后续步骤, 只有promise调用then的时候,then里面的函数才会被推入微任务中
var promise = new Promise(function(reslove, reject) {
    if(异步操作成功) {
        reslove(value);
    }else {
        reject(error);
    }
})
  1. 状态改变(且状态改变之后就不会再改变了)
    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

  1. await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果;
    如果不是 promise , 把这个直接量,作为 await表达式的结果
  2. 特别注意:如果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

async函数的含义和用法

  1. 异步操作解决方案
    回调函数-> promise对象-> generator函数->async await
  2. async函数就是Generator函数的语法糖
  3. async函数优点
    内置执行器【Generator函数执行必须靠执行器】
    更广的适用性【co函数库约定,yield命令后只能是Thunk函数或Promise对象;await后面可以跟Promise对象和原始类型的值
  4. 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不在同一个队列中。

generator

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值