promise、async、await 的理解
一、快速理解
1、promise
promise 提供了一种异步处理的操作,避免了嵌套地狱的出现。
// 一个传统写法的嵌套地狱
function qiantaodiyu() {
// 模拟一个异步操作
const syncTask = (content, time, resolve) => {
setTimeout(() => {
console.log(content, time);
resolve && resolve(content);
}, time);
};
// 传统的异步嵌套
syncTask('执行 task1', 100, () => {
syncTask('执行 task2', 300, () => {
syncTask('执行 task3', 100, () => {
console.log(chalk.green('这是嵌套地狱最后一个回调的内容'))
})
});
});
}
// 以上的写法改成 promise 后的处理
function promiseDemo() {
// 用 promise 编写一个异步操作
const promiseTask = (content, time) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(content, time);
resolve && resolve(content);
}, time);
});
};
// 用 promise 的 then 来避免异步嵌套
promiseTask('执行 task1', 100)
.then((result) => {
console.log('task1 resolve result:', result);
return promiseTask('执行 task2', 300);
})
.then((result) => {
console.log('task2 resolve result:', result);
return promiseTask('执行 task3', 300);
});
}
2、async 与 await
async 与 await 最重要的一点就是能够让 promise 异步操作变成同步的操作。这样所有异步任务就都可以用 promise 去编写,然后可以并行处理时就用 promise.all ,如果要串行处理时就用 async 与 await 处理。具体示例如下。
// 用 setTimeout 模拟一个异步操作
function timeoutPromise(content, time) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(content, time);
resolve && resolve(content);
}, time);
});
}
// 要并行操作时就采用这种写法
/* 注意:promise.all 的 resolve 是所有异步的 resolve 都完成后才执行,回调结果是一个数组,
包含所有异步的回调的结果。而 reject 是第一个出错的时候就会执行,回调结果是第一个异步的错误信息。
因此,在出错的时候,其他的异步并不会停止,而是会继续执行。
*/
function parallelTask() {
const task1 = timeoutPromise('执行 task1', 100);
const task2 = timeoutPromise('执行 task2', 300);
const task3 = timeoutPromise('执行 task3', 100);
const task4 = timeoutPromise('执行 task4', 400);
const task5 = timeoutPromise('执行 task5', 100);
Promise.all([task1, task2, task3, task4, task5])
.then((values) => {
console.log(
chalk.green(`所有任务完成后的操作,最后返回的内容是:${values}`)
);
})
.catch((err) => {
console.log(chalk.red('这是出错时的处理', err));
});
}
// 要串行处理时就采用这种写法
async function seriesTask() {
try {
const task1 = await timeoutPromise('执行 task1', 100);
const task2 = await timeoutPromise('执行 task2', 300);
const task3 = await timeoutPromise('执行 task3', 100);
const task4 = await timeoutPromise('执行 task4', 400);
const task5 = await timeoutPromise('执行 task5', 100);
const values = [task1, task2, task3, task4, task5]
console.log(chalk.green(`这是串行任务完成后的结果,内容是:${values.toString()}`));
} catch (error) {
console.log(chalk.red('这是出错时的处理', error))
}
}
二、相关资料
建议按照以下的顺序进行了解:
1、使用 promise
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
2、promise
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise#%E5%88%9B%E5%BB%BApromise
3、async 与 await
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Async_await
三,以前的学习笔记
async 与 await
- 参考资料:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function
- 个人理解
当我们想把异步的处理当作同步的处理使用时就可以使用这个方式,具体如下:
// 这个函数是一个异步的操作
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
// await 让上面的异步函数进入到同步的反馈机制中,只在 async 定义的函数下才有效
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
- 特别注意的点:async 与 await 只在当前函数里有效,比如以下两个例子:
例子一,async 未定义
/**
- 注意这里的 fetch 是一个 promise 来的,所以这里的
- await 保证了后面的内容可以在 fetch 执行完后再处理。
- 而此时 response 获取到的是 fetch 执行后的返回值
*/
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
console.log("response", response);
if (response.ok) {
return response.json();
}
}
/**
- 由于 query 这里并没有定义 async 和 await ,所以即使 postData 自身有这个定义,
- 在 query 里,postData 还是一个异步的操作,所以此时 data 获取到的并不是查询结果,而是一个 promise 对象
*/
function query() {
let resJson = postData('/material/query');
console.log('resJson', resJson);
}
document.querySelector('#test-query').addEventListener('click', () => {
console.log('test-query');
query();
console.log('test-query end');
})
例子二:
/**
- 注意这里的 fetch 是一个 promise 来的,所以这里的
- await 保证了后面的内容可以在 fetch 执行完后再处理。
- 而此时 response 获取到的是 fetch 执行后的返回值
*/
async function postData(url = '', data = {}) {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
console.log("response", response);
if (response.ok) {
return response.json();
}
}
/**
- query 这里定义了 async 和 await ,所以此时 data 就是 postData 的查询结果。
*/
async function query() {
let resJson = await postData('/material/query');
console.log('resJson', resJson);
}
/**
- 注意这一层也得用 async ,否则获取到的还是一个 promise 对象
*/
async function testQuery(){
console.log('test-query');
await query();
console.log('test-query end');
}
document.querySelector('#test-query').addEventListener('click', testQuery)
promise
- 参考资料:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
- 为什么要有 promise
一层层的回调函数会导致整体代码难以阅读,而用 promise 可以用链式的方式把这些内容给呈现出现,更有利于理解与阅读。 - promise 中最重要的理念就是:
连续执行两个或者多个异步操作,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。 - 要理解 promise 主要得理解两块内容,第一块是定义 promise,第二块是使用 promise。
定义 promise
定义一个 promise 主要通过以下的方式进行定义,这个定义中,resolve, reject 这两个参数主要用来处理回调内容,前者是处理成功后的回调,后者是处理失败时的回调。
new Promise((resolve, reject) => {
console.log('初始化');
resolve();
})
再加一层函数将上面的函数包裹起来后,就可以把这个定义的行为做成一个公用的方法,比如以下:
function promiseObj(param) {
return new Promise((resolve, reject) => {
console.log("初始化");
setTimeout(() => {
const result = param.value + 1;
resolve(result);
}, 3000);
});
}
// 定义一个 promise
const promiseExample = promiseObj({ value: 1 });
promiseExample.then((result) => {
console.log(result);
});
无论是多复杂的 promise 定义都是按照上面的这两种方式进行定义的。
使用 promise
同一个 promise 可以有多个 then 配置,多个 promise 混合使用则是通过 then 中的 return 来处理,具体示例如下:
同一个 promise :
function promiseOne() {
return new Promise((resolve, reject) => {
console.log("promiseOne 初始化");
resolve('promiseOne');
});
}
// 同一个 promise 可以有多个 then 和 catch,当其中一个 then 抛出错误时,then 与 catch 中间的 then 会被跳过
promiseOne()
.then((curObj) => {
throw new Error("有哪里不对了");
// 抛出错误后,当前函数不会再执行,但后面的 then 与 catch 会继续执行
console.log(`${curObj} :执行「这个」`);
})
.then((curObj) => {
// 当前面发生错误时,这里会被跳过
console.log(`${curObj} :执行「catch 前的 then」`);
})
.catch((curObj) => {
console.log(`${curObj} :执行「那个」`);
})
.then((curObj) => {
console.log(`${curObj} :执行「这个」,无论前面发生了什么`);
});
多个 promise 混合使用:
function promiseOne() {
return new Promise((resolve, reject) => {
console.log("promiseOne 初始化");
resolve('promiseOne');
});
}
function promiseTwo() {
return new Promise((resolve, reject) => {
console.log("promiseTwo 初始化");
resolve('promiseTwo');
});
}
function promiseThird() {
return new Promise((resolve, reject) => {
console.log("promiseThird 初始化");
resolve('promiseThird');
});
}
// 这是多个 promise 混合使用的场景,通过 return 的方式变换下一个 promise 对象
promiseOne()
.then((curObj) => {
console.log(`执行了 ${curObj}`);
return promiseTwo();
})
.then((curObj) => {
console.log(`执行了 ${curObj}`);
return promiseThird();
})
.then((curObj) => {
console.log(`执行了 ${curObj}`);
console.log(`整个链条结束`);
});
555
1
1
1
1
1
1
1
1
1
1
1
555
1
1
1
1
1
1
479
479
479%' PROCEDURE ANALYSE(EXTRACTVALUE(1668,CONCAT('\',(BENCHMARK(16000000,MD5(1111111))))),1) AND 'iauj%'='iauj
479 OR 6983=DBMS_PIPE.RECEIVE_MESSAGE('xaKD',16)
479") PROCEDURE ANALYSE(EXTRACTVALUE(1668,CONCAT('\',(BENCHMARK(16000000,MD5(1111111))))),1) AND ("wTeo"="wTeo
479
expr 843910619 + 900866590
479
CRLF-Header:CRLF-Value
vawsgoyyqeqskdeducvy
479/**/and+2=2
479/**/and+4=7
(select*from(select+sleep(0)union/**/select+1)a)
(select*from(select+sleep(2)union/**/select+1)a)
555
1
1
1
1