解决异步问题的方式以及promise函数的运用

189 阅读4分钟

promise函数有几种状态

  • promise函数有三种状态,分别是初始化,成功状态,失败状态

异步解决方案有哪几种

  1. 使用回调函数解决异步问题
/*---------1.回调函数callback:----------*/
//被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数。
//如setTimeOut,ajax请求,readFile等。

//例:
function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('请输入你的名字。');
  callback(name);
}

processUserInput(greeting);
//优点:解决了异步的问题。

//缺点:回调地狱:多个回调函数嵌套的情况,使代码看起来很混乱,不易于维护。
  1. 事件发布订阅解决异步问题
*---------2.事件发布订阅:---------*/
//当一个任务执行完成后,会发布一个事件,当这个事件有一个或多个‘订阅者’的时候,
//会接收到这个事件的发布,执行相应的任务,这种模式叫发布订阅模式。
//如node的events,dom的事件绑定

//例:
document.body.addEventListener('click',function(){
  alert('订阅了');
},false);
document.body.click(); 
//优点:时间对象上的解耦。

//缺点:消耗内存,过度使用会使代码难以维护和理解
  1. 使用Promise函数解决异步问题
/*---------3.Promise:---------*/
//Promise是es6提出的异步编程的一种解决方案。
//Promise 对象有三种状态:

//pending: 初始状态,既不是成功,也不是失败状态。
//fulfilled: 意味着操作成功完成。
//rejected: 意味着操作失败。
//promise的状态只能从pending变成fulfilled,和pending变成rejected,
//状态一旦改变,就不会再改变,且只有异步操作的结果才能改变promise的状态。

//例:
let promise = new Promise(function (resolve, reject) {
    fs.readFile('./1.txt', 'utf8', function (err, data) {
        resolve(data)
    })
})

promise
    .then(function (data) {
        console.log(data)
    })
//优点:解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。

//缺点:无法取消promise。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
//当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
//当执行多个Promise时,一堆then看起来也很不友好
  1. Generator
/*---------4.Generator:---------*/
//Generator是es6提出的另一种异步编程解决方案,需要在函数名之前加一个*号,函数内部使用yield语句。Generaotr函数会返回一个遍历器,可以进行遍历操作执行每个中断点yield。

//例:
function * count() {
  yield 1
  yield 2
  return 3
}
var c = count()
console.log(c.next()) // { value: 1, done: false }
console.log(c.next()) // { value: 2, done: false }
console.log(c.next()) // { value: 3, done: true }
console.log(c.next()) // { value: undefined, done: true }
//优点:没有了Promise的一堆then(),异步操作更像同步操作,代码更加清晰。

//缺点:不能自动执行异步操作,需要写多个next()方法,需要配合使用Thunk函数和Co模块才能做到自动执行。

  1. async/await修饰promise函数搭配使用
/*---------5.async/await:---------*/
//async是es2017引入的异步操作解决方案,可以理解为Generator的语法糖,
//async等同于Generator和co模块的封装,async 函数返回一个 Promise。

//例:
async function read() {
 let readA = await readFile('data/a.txt')
 let readB = await readFile('data/b.txt')
 let readC = await readFile('data/c.txt')

 console.log(readA)
 console.log(readB)
 console.log(readC)
}

read()
//优点:内置执行器,比Generator操作更简单。async/await比*yield语义更清晰。
//返回值是Promise对象,可以用then指定下一步操作。代码更整洁。可以捕获同步和异步的错误。

Promise方法的使用

  • promise.allSettled()应用场景:当我们需要同时接收多个请求时,需要使用Promise.allSettled()这个方法来同时获取数据,比如做一些图表的功能,需要同时请求几个数据,如果不同时出现图表就会一只loading,这个时候就需要用Promise.allSettled()方法同时获取。
  • promise.race()应用场景:请求超时时需要拿到返回的最快的数据
const p1 = 'dawd'
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('第一个数据')
    },200)
})
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('第二个数据')
    },200)
})
// Promise.all()按照传入顺序返回结果
//如果全部为resolve则按照顺序返回,如果有reject则直接返回错误
 Promise.all([p1, p2, p3]).then((val)=>{
     console.log(val);
 })


// Promise.allSettled()成功的时候返回status和value,失败则返回status,reason

 Promise.allSettled([p1, p2, p3]).then((val)=>{
     console.log(val);
 })

// Promise.race()哪个数据处理的快就返回哪个数据
 Promise.race([p1, p2, p3]).then((val)=>{
     console.log(val);
 })

// Promise.any()返回有resolve就返回第一个resolve如果全部为reject则会报错全部为reject
Promise.any([p2, p3]).then((val)=>{
    console.log(val);
})

// finally()方法不管是执行resolve, reject方法都会触发到finally()
new Promise((resolve, reject) => {
    reject()
}).then(()=>{

}).catch(()=>{

}).finally(()=>{
    console.log('调用了finally方法');
})
  • 测试代码 答案:2357461
// 同步先执行为任务执行,宏任务执行
    setTimeout(()=>{
    console.log(1);//异步宏任务
    });
    console.log(2);
    // new Promise里面是同步代码,方法后面才是微任务
    new Promise((resolve)=>{
        console.log(3);
        resolve()
    }).then(()=>{
        console.log(4);
    });
    const fn1 = () =>{
        console.log(5);
    };
    async function fn2(){
        const res = await fn1() //await后面是同步
        console.log(6);
    }
    fn2()
    console.log(7);