js中的同步异步问题(Promise以及async和await)

346 阅读4分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

ES6模块化

ES6模块化规范

每个 js 文件都是一个独立的模块

导入其它模块成员使用 import 关键字

向外共享模块成员使用 export 关键字

想要使用ES6的导入导出必须要满足两个条件

  1. 确保安装了 v13.0.0 或更高版本的 node.js
  1. 在 package.json 的根节点中添加 "type": "module" 节点

1661435872046.png 如图上,要将 package.json 的根节点中添加 "type": "module" 节点

默认导入导出

默认导出的语法: export default 默认导出的成员

默认导入的语法: import 接收名称 from '模块路径'

主模块导入子模块的内容

1661436403143.png

子模块默认导出

1661436413658.png

按需导入导出

按需导出的语法: export const s = 5

按需导入的语法: import { 按需导入的名称 } from '模块路径'

按需导入必须解构!

子模块按需导出

1661436572397.png 主模块接收

1661436609587.png

注意:按需导入可以重命名,使用as关键字

只导入,不接收

如果只想单纯地执行某个模块中的代码,并不需要得到模块中向外共享的成员。

此时,可以直接导入并执行模块代码,语法:import '模块的路径'

1661436691204.png

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大

从语法上说,Promise 是一个对象,ES6将其写进了语言标准,统一了用法,使用的使用需要 new

Promise 可以理解为一个容器,里面可以编写异步程序的代码

  1. 创建Promise对象
let p = new Promise((resolve, reject) => {
    // ... some code
    if (/* 异步操作成功 */) {
        resolve(value);
    } else {
        reject(error);
    }
});
​

new Promise()

必须传入一个函数作为Promise的参数,这个函数在 new Promise的时候就会执行

函数有 resolve 和 reject 两个形参

函数就相当于一个容器,可以将异步任务放到这里

将异步任务成功的结果传给 resolve 函数;将失败的信息传给 reject 函数

  1. 通过then获取结果
p.then(
    result => { /* 获取成功的结果 */ },
    err => { /* 获取失败的结果 */ }
);

then方法接收两个函数类型的参数,分别用于接收 resolve 的值 和 reject 的值

then方法也可以只接收一个参数,表示只接收 resolve 的值,失败的结果可以通过链式调用catch方法捕获

p.then(
    result => { /* 获取成功的结果 */
        console.log(result);
    },
    err => { /* 获取失败的结果 */
        console.log(err);
    }
);

同步异步

new Promise 和 new 其他对象一样,是同步任务

获取结果时(调用 resolve 触发 then方法时)是异步的

console.log(1);
new Promise((resolve, reject) => {
    console.log(2);
    resolve();
    console.log(3);
}).then(res => {
    console.log(4);
})
console.log(5);
​

new Promise时,传入的函数会自动执行

所以代码基本上是按顺序执行的

但是 resolve 函数属于异步任务,它最后执行

所以输出顺序是:12354

then方法的链式调用

new Promise((resolve, reject) => {
    resolve(1);
}).then(r1 => {
    console.log(r1); // 1
    return new Promise/* resolve(2); 其他代码略 */ )
}).then(r2 => {
    console.log( r2 ); // 2
})

then方法可以链式调用

如果前一个then返回一个普通值,则后一个then可以得到这个值

如果前一个then返回一个 Promise 对象,则后一个 then 可以得到 Promise 对象成功状态的结果

asyncawait 修饰符

async 和 await 是 ES2017 中提出来的

async 和 await 两个关键字的出现,简化的 Promise 的使用

async 用于修饰一个 function

async 修饰的函数,总是返回一个 Promise 对象

函数的返回值,将自动包装在 resolve 的 promise 中

await 只能出现在 async 函数内

await 让 JS 引擎等待直到promise完成并返回结果

语法:let value = await promise对象; // 等待promise对象的结果,然后将结果赋值给 value

由于await需要等待promise执行完毕,所以 await会 暂停函数的执行,但不会影响其他同步任务

  1. await只能出现在async修饰的函数中!
  1. await后面跟随的是一个promise对象;
  1. await返回的是: Promise对象中的then()中的回调函数中的参数res;
  1. await能停止代码执行,让后面的同步代码,先执行;
async function abc() {
    let a = await myReadFile('./a.txt');
    let b = await myReadFile('./b.txt');
    let c = await myReadFile('./c.txt');
    console.log(a);
    console.log(b);
    console.log(c);
}
abc();
//aa bb cc

特点

console.log(1);
async function abc() {
    console.log(2);
    await console.log(3) // 输出3之后,遇到await,暂停函数执行
    console.log(4);
}
abc();
console.log(5);

左右结构的代码,右先执行,所以先输出3,在使用await修改 log 的返回值

由于await 会暂停函数的执行,所以最后输出 4 (因为它在 await 之后输出的)