JavaScript异步函数和Promise的使用

首先什么是同步什么是异步?
 

同步:同步操作是指按照它们在代码中出现的顺序依次执行的操作。在同步操作中,当前操作未完成前,后续操作会等待(即被阻塞),直到当前操作完成。

异步:异步操作是指可以在不等待当前操作完成的情况下继续执行后续代码的操作。在异步操作中,通常会启动一个操作,然后立即继续执行后续代码,而操作的结果会在稍后处理。

举个不太恰当的例子:同步就像是一条单行车道 ,无论你的车有多块都要等前面的车先通过,在这之前你都是被堵着的(被阻塞)。异步就像多行车道,可以让多辆汽车同时通过。

异步函数的使用

async函数:

语法:
async function name([param[, param[, ... param]]]) {
        statements
}
- name: 函数名称。
- param: 要传递给函数的参数的名称。
- statements: 函数体语句。

返回值:
async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。

例子:

async function helloAsync(){
        return "helloAsync";
}

console.log(helloAsync()) // Promise { "helloAsync"}

helloAsync().then(v=>{
        console.log(v);// 输出:helloAsync
})

await操作符:

作用:
await 操作符用于等待一个 Promise 对象。

async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。

await 关键字仅在 async function 中有效。如果在 async function 函数体外使用 await ,你只会得到一个语法错误。

语法:
[return_value] = await expression;
expression: 一个 Promise 对象或者任何要等待的值

返回值:
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。
如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。

例子:

function testAwait (x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}
 
async function helloAsync() {
  var x = await testAwait ("hello world");
  console.log(x); 
}
helloAsync ();
// 输出:hello world

正常情况下,await 命令后面是一个 Promise 对象,它也可以跟其他值,如字符串,布尔值,数值以及普通函数。

 

function testAwait(){
   return new Promise((resolve) => {
       setTimeout(function(){
          console.log("testAwait");
          resolve();
       }, 1000);
   });
}
 
async function helloAsync(){
   await testAwait();
   console.log("helloAsync");
 }
helloAsync();
//输出结果:
// testAwait
// helloAsync

 await针对所跟不同表达式的处理方式:
- Promise 对象:await 会暂停执行,等待 Promise 对象 resolve,然后恢复 async 函数的执行并返回解析值。
- 非 Promise 对象:直接返回对应的值。


Promise的使用
首先我们来看看处理多个异步函数时使用嵌套的方法来解决异步函数执行顺序的问题
 

function asyncFn(fn1, fn2, fn3) {
    setTimeout(() => {
        //处理第一个异步任务
        fn1()
        setTimeout(() => {
            //处理第二个异步任务
            fn2()
            setTimeout(() => {
                //处理第三个异步任务
                fn3()
            }, 2000)
        }, 2000)
    }, 2000)
}

function fn1() {
    console.log('执行1')
}

function fn2() {
    console.log('执行2')
}

function fn3() {
    console.log('执行3')
}

asyncFn(fn1, fn2, fn3)

看似没有问题,但如果我要解决三十个这样的异步函数就会造成可读性变得极差。这便是令人头疼的“回调地狱”。

 解决上述问题方法
- Promise可以使用.then()方法链式处理异步逻辑
- Promise可以使用.catch()方法处理异步操作失败的情况
- Promise提供.all()、.race()方法支持处理多个Promise对象的结果。

值得注意的是:Promise 是用来管理异步编程的,它本身不是异步的,new Promise 的时候会立即把 executor 函数执行,只不过我们一般会在 executor 函数中处理一个异步操作。 Promise 采用了回调函数“延迟绑定技术”,在执行 resolve 函数的时候,回调函数还没有绑定,那么只能推迟回调函数的执行。 Promise 对象的错误**具有“冒泡”性质,会一直向后传递。

 Promise基本实现
- 1.每个promise都有三个状态pending等待态,fulfilled成功态,rejected失败态。

​​​​​​- 2.每个promise需要有一个then方法,.then()方法接受两个回调函数,一个是成功的回调另一个是失败的回调。
- 3.new Promise中传递的函数会立即执行。
- 4.promise对象的状态一旦更改后,即不能再改变。(一旦成功就不能失败,一旦失败就不能成功)。
- 5.当promise抛出异常后,也会变为失败态。


例子:
简单用法

let promise = new Promise((resolve,reject) => {
		// 默认状态:等待态
		fn1(reject);
	}).then((value) => {
		fn2();
	},(reason) => { //当为错误态的回调函数,注意根据代码结构它还处于,then()下。
		console.log(reason)
		fn3()
	});

核心用法:
 

// 模拟三个需要顺序执行的异步任务
const task1 = () => {
  return new Promise((resolve) => {
    setTimeout(() => resolve("第一步完成"), 500);
  });
};

const task2 = (input) => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`${input} → 第二步完成`), 300);
  });
};

const task3 = (input) => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`${input} → 第三步完成`), 200);
  });
};

// 链式调用
task1()
  .then(task1Result => task2(task1Result))
  .then(task2Result => task3(task2Result))
  .then(finalResult => console.log("最终结果:", finalResult))
  .catch(error => console.error("链中出错:", error));

更加简单的ES7写法:

//ES7
async function show() {
    try {
        await fn1();
        await fn2();
        await fn3();
    } catch (e) {
        console.log(e);
    }
}

一定注意:
1.Promise是一个类,使用的时候需要new Promise来产生一个promise实例
2.构造函数中需要传递函数参数executor()
3.executorl函数中有两个参数resolve(value),reject(reason)
调用resolve:会让promise变成成功
调用reject会变成失败: pending等待态,fulfilled成功态,rejected失败态
一但状态发生变化后不能再修改状态
4.每个promise实例都有一个then方法,会有两个参数onfulfilled,onrjected
5.如果不调用resolve.此时promise不会成功也不会失败(如果发生异常也会认为是失败)
6.resolve之后不能reject,相反也是
7.executor是立刻执行的

Promise的常用方法:
1.resolve(定义成功后回调)
 

        //resolve
        Promise.resolve('成功值').then(res => {
            console.log(res, 'resolve的使用')
        })
        
        //等同于
        new Promise((resolve, reject) => {
            resolve('成功值')
        }).then(res => {
            console.log(res, 'resolve的使用')
        })

 2.reject(定义失败后回调)

        //reject
        Promise.reject('失败值').then(res => {
            console.log(res, '不会走成功')
        }, rej => {
            console.log(rej, '会走失败')
        })
        
        //等同于
        new Promise((resolve, reject) => {
            reject('失败值')
        }).then(res => {
            console.log(res, '不会走成功')
        }, rej => {
            console.log(rej, '会走失败')
        })

3.then(根据状态值进行异步处理)
then方法是promise的核心方法。
当一个promise执行到then的时候,说明这个promise对象的状态值已经确定了,也就是只要执行到then方法里面,就说明前面的异步执行完成了,你可以根据返回的状态值进行异步的操作了。
then是一个函数,接受两个参数,这两个参数都是函数,参数一处理成功回调,参数2处理失败回调

// 模拟异步读取文件操作,返回一个 Promise
function readFile(fileName) {
    return new Promise((resolve, reject) => {
        // 模拟异步操作,这里用 setTimeout 模拟延迟
        setTimeout(() => {
            const success = Math.random() > 0.3; // 模拟 70% 的成功率
            if (success) {
                const content = `这是 ${fileName} 的内容`;
                resolve(content);
            } else {
                reject(new Error(`无法读取 ${fileName}`));
            }
        }, 1000);
    });
}

// 使用 then 方法处理 Promise 的结果
readFile('example.txt')
   .then(
        (content) => {
            console.log('成功读取文件:', content);
        },
        (error) => {
            console.error('读取文件失败:', error.message);
        }
    );

4.catch(Promise内发生意外报错回调处理)

let prm = new Promise((resolve, reject) => {
            let a = null
            console.log(a.a)
            reject('失败')
        })
        prm.then(res => {
            console.log(res, '进入then方法')
        }).catch(error => {
            console.log(error, '进入error')
        })

5.all(所有异步都执行完后得到结果)

**异步都成功**

        let prm1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('执行prm1成功')
            }, 3000)
        })
        
        let prm2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('执行prm2成功')
            }, 1000)
        })
        
        let prm3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('执行prm3成功')
            }, 5000)
        })
        
        Promise.all([prm1, prm2, prm3]).then(res => {
            console.log(res, '三个都执行完毕')
        })
**异步中有失败**

        let prm1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('执行prm1成功')
            }, 3000)
        })
        let prm2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('执行prm2成功')
            }, 1000)
        })
        let prm3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('执行prm3失败')
            }, 5000)
        })
        Promise.all([prm1, prm2, prm3]).then(res => {
            console.log(res, '三个都执行完毕--成功')
        }, rej => {
            console.log(rej, '三个都执行完毕--有不成功')
        })

6.allSettled(all的改良版,可以获取全部任务的状态)
all方法能获取所有任务都成功之后的值,但是如果多个任务有成功有失败,就无法全部获取所有状态,但是allSettled可以做到。
可以理解成all()一错全错,类似逻辑“&&”的处理方法不会再检查后续任务。allSettled则是检查全部任务的是否完成最后给出结果。

        //allSettled方法
        let pr1 = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('pr1成功')
            },2000)
        })
        let pr2 = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                reject('pr2失败')
            },3000)
        })
        let pr3 = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('pr3成功')
            },3000)
        })
        Promise.allSettled([pr1,pr2,pr3]).then(res=>{
         console.log(res,'获取所有状态')
        })

7.race(获取多个异步中最优先执行完成的结果)
 

成功的情况

    //race方法
    let prm1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('执行prm1成功')
        }, 3000)
    })
    let prm2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('执行prm2成功')
        }, 1000)
    })
    let prm3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('执行prm3失败')
        }, 5000)
    })
    Promise.race([prm1, prm2, prm3]).then(res => {
        console.log(res, '成功逻辑')
        //res获取到的是最先执行完的prm2
    },
        rej => {
            console.log(rej, '失败逻辑')
 
        })
失败的情况

    let prm1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('执行prm1成功')
        }, 3000)
    })
    let prm2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('执行prm2失败')
        }, 1000)
    })
    let prm3 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('执行prm3失败')
        }, 5000)
    })
    Promise.race([prm1, prm2, prm3]).then(res => {
        console.log(res, '成功逻辑')
    },
        rej => {
            console.log(rej, '失败逻辑')
 	    //因为prm第一个执行完毕所有输出结果
            //执行prm2失败 失败逻辑
        })

8.any(任何一个成功就是成功)

        //any方法
        let pr1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('pr1成功')
            }, 2000)
        })
        let pr2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('pr2失败')
            }, 3000)
        })
        let pr3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('pr3失败')
            }, 3000)
        })
        Promise.any([pr1,pr2,pr3]).then(res=>{
         console.log(res,'成功')
         //输出:pr1成功 成功
        })
        Promise.any([pr2,pr3]).then(res=>{
         console.log(res,'失败')
         //输出:AggregateError: All promises were rejected 失败
        })

finally(不管一个promise任务执行成功还是失败,执行完毕后都会进入这个方法)
 

        //finally方法
        //成功
        let prm4 = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve('成功的值')
            },2000)
        })
        prm4.then(res=>{
            console.log(res,'成功')
        }).finally(val=>{
            console.log(val,'finally方法')
        })
 
        //失败
        let prm5 = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                reject('失败原因')
            },2000)
        })
        prm5.catch(rej=>{
            console.log(rej,'失败')
        }).finally(val=>{
            console.log(val,'finally方法')
            //无论成功与否都执行
        })

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值