关于异步
JavaScript脚本执行是“单线程”(脚本解释引擎是单线程的),但会GUI线程,网络请求线程等
JS引擎基于事件驱动,内部维持一个执行循环的任务,持续读取回调队列的任务。
任务分为同步任务和异步任务:
- 同步任务是指在主线程排队执行的任务,只有前一个执行完毕,后一个才会执行。
- 异步任务是指由运行环境执行,任务完成后,将事先定义的回调函数推入主线程的任务队列,当主线程的执行栈清空之后会读取任务队列的回到函数,当任务队列被读取完毕之后,主线程接着执行,从而进入一个无限循环,这就是事件循环。
异步任务队列分为:
macro-task: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, Promises(这里指浏览器实现的原生 Promise), Object.observe, MutationObserver
一个事件循环,多个任务队列
每一次事件循环(one cycle of the event loop),只处理一个 (macro)task。待该 macrotask 完成后,所有的 microtask 会在同一次循环中处理
关于Promise
Promise是一个函数返回的对象,代表一个异步操作的完成或失败。
Promise链式调用风格,每一个 Promise 都代表了链中另一个异步过程的完成,避免callback形式的嵌套调用。一种用处,串行异步任务调用,传递上个异步任务结果。
(function simple () {
// 创建Promise对象,Promise参数传入的是一个函数,此函数有resolve, reject 两个参数
let promise = new Promise((resolve, reject) => {
// 调用resolve, resolve是Promise内定义的函数,切换当前Promise从 'pending' 到 'fulfilled' 状态
setTimeout(() => resolve('Success'), 2000)
});
// 添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.
// onResolved函数的参数就是上面resolve传入的参数
promise .then((msg) => {
console.log(`Hello Message is ${msg}`)
}, () => {
console.log('oops! its rejected')
})
}())
参考模拟实现源码:https://github.com/xieranmaya/Promise3/blob/master/Promise3.js
链式调用中的 promise 们就像俄罗斯套娃一样,是嵌套起来的,但又像是一个栈,每个都必须从顶端被弹出。链式调用中的第一个 promise 是嵌套最深的一个,也将是第一个被弹出的。
const myPromise =
(new Promise(myExecutorFunc))
.then(handleFulfilledA, handleRejectedA)
.then(handleFulfilledB)
.then(handleFulfilledC, handleRejectedC)
.then(handleFulfilledD, handleRejectedD)
.catch(handleRejectedAny);
// (promise D, (promise C, (promise B, (promise A) ) ) )
关于async和await
async和await是Promise的语法糖,比使用Promise更易写和易读
// 用async关键词后,hello()将是一个返回Promise的异步函数
async function hello() { return "Hello" };
hello();
// 输出 ƒ AsyncFunction() { [native code] }
console.log(Object.getPrototypeOf(async function(){}).constructor)
实际例子
// Promise写法
fetch('coffee.jpg')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
} else {
return response.blob();
}
})
.then(myBlob => {
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
})
.catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
// await写法
async function myFetch() {
let response = await fetch('coffee.jpg');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
} else {
let myBlob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
}
}
myFetch()
.catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
参考:
https://www.cnblogs.com/10yearsmanong/p/12212512.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await