#### JS 異步編程
#### http://www.reibang.com/p/9bfb68c585bc
#### https://blog.csdn.net/weixin_48820137/article/details/108850610
#### https://juejin.im/post/6877438201657557005/
#### JavaScript異步編程
單線程: JS執(zhí)行環(huán)境中負責執(zhí)行代碼的線程只有一個
優(yōu)點: 更安全更簡單
缺點: 耗時任務阻塞
#### 同步模式---調用棧(Call stack)排隊執(zhí)行
#### 異步模式
不會去等待這個任務的結束才開始下一個任務
開啟過后立即往后執(zhí)行下一個任務
后續(xù)邏輯一般會通過回調函數(shù)的方式定義
消息隊列(Queue)和事件循環(huán)(Event loop)
運行環(huán)境提供的API是以同步或異步模式的方式工作
**EventLoop** 是一種循環(huán)機制 外永,不斷去輪詢一些隊列 策橘,從中找到 需要執(zhí)行的任務并按順序執(zhí)行的一個執(zhí)行模型回论。
**消息隊列** 是用來存放宏任務的隊列犹撒, 比如定時器時間到了, 定時間內傳入的方法引用會存到該隊列逻卖, ajax回調之后的執(zhí)行方法也會存到該隊列杈绸。
一開始整個腳本作為一個宏任務執(zhí)行。執(zhí)行過程中同步代碼直接執(zhí)行檬贰,宏任務等待時間到達或者成功后,將方法的回調放入宏任務隊列中缺亮,微任務進入微任務隊列翁涤。
當前主線程的宏任務執(zhí)行完出隊,檢查并清空微任務隊列萌踱。接著執(zhí)行瀏覽器 UI 線程的渲染工作葵礼,檢查web worker 任務,有則執(zhí)行。
然后再取出一個宏任務執(zhí)行。以此循環(huán)...
**宏任務**可以理解為每次執(zhí)行棧執(zhí)行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調并放到執(zhí)行棧中執(zhí)行)。
瀏覽器為了讓 JS 內部宏任務 與 DOM 操作能夠有序的執(zhí)行,會在一個宏任務執(zhí)行結束后芦缰,在下一個宏任務執(zhí)行開始前,對頁面進行重新渲染高职。
? 宏任務包含:script(整體代碼)藐吮、setTimeout、setInterval卤档、I/O蝙泼、UI交互事件、MessageChannel 等
**微任務**可以理解是在當前任務執(zhí)行結束后需要立即執(zhí)行的任務劝枣。也就是說汤踏,在當前任務后,在渲染之前舔腾,執(zhí)行清空微任務溪胶。
所以它的響應速度相比宏任務會更快,因為無需等待 UI 渲染稳诚。
微任務包含:Promise.then哗脖、MutaionObserver、process.nextTick(Node.js 環(huán)境)等
#### Promise
三個狀態(tài) Pending Fulfilled-onFulfilled Rejected-onRejected
狀態(tài)更改之后不可修改
#### promise 基本用法
const promise = new Promise(function(resolve, reject){
? ? // foo()
? ? // throw new Errow('error')
? ? resolve(100)
? ? // reject(new Error("promise rejected"))
})
// promise.then(function(value){
//? ? console.log('resolved', value)
// }, function(error){
//? ? console.log('rejected', error)
// })
// console.log('end')
#### Promise 常見誤區(qū)---回調嵌套
#### Promise 鏈式調用
then方法會返回一個全新的Promise對象
后面的then方法就是在為上一個then返回的Promise注冊回調
前面then方法中的回調函數(shù)的返回值會作為后面then方法回調的參數(shù)
如果回調中返回的是Promise, 那么后面then方法的回調會等待它的結束
let promise2 = promise.then(function(value){
? ? console.log('resolved', value)
}, function(error){
? ? console.log('rejected', error)
}) .then(function(value){
? ? console.log('resolved', value)
}, function(error){
? ? console.log('rejected', error)
}) .then(function(value){
? ? console.log('resolved', value)
}, function(error){
? ? console.log('rejected', error)
})
console.log(promise2 === promise)
promise.then(function(value){
? ? console.log('resolved', value)
}).catch(error => {
? ? console.log("error", error)
})
#### Promise 異常處理
Promise實例的catch方法 then方法中的失敗回調
區(qū)別: (1)then注冊失敗回調只能捕獲到前一個promise的異常
(2)catch是給整個Promise鏈條注冊的失敗回調
#### Promise 靜態(tài)方法
resolve() reject()
Promise 靜態(tài)方法 Promise.resolve() Promise.reject()
三種是等價的? 有thenable接口的函數(shù)
Promise.resolve('f00').then( value => {
? ? console.log('resolve', value)
})
Promise.resolve({
? ? then: (onFulfilled, onRejected) => {
? ? ? ? onFulfilled('f00')
? ? }
}).then(value => {
? ? console.log(value)
})
new Promise((resolve, reject) => {
? ? resolve('f00')
}).then(value => {
? ? console.log('new', value)
})
Promise.reject(new Error('rejected')).catch(error => {
? ? console.log('error', error)
})
#### Promise 并行執(zhí)行
all()方法 race()方法
#### Promise 執(zhí)行時序 / 宏任務 微任務
微任務: 提高整體的響應能力
Promise 執(zhí)行時序 / 宏任務 微任務
console.log('global start')
setTimeout(()=>{
? ? console.log('setTimeout1')
}, 1000)
setTimeout(()=>{
? ? console.log('setTimeout')
}, 100)
Promise.resolve().then(()=>{
? ? console.log('promise')
}).then(()=>{
? ? console.log('promise1')
})
console.log('global end')
#### Generator異步方案
//Generator異步方案
function *foo(){
? ? console.log("start")
? ? try{
? ? ? ? const res = yield 'foo'
? ? ? ? console.log(res, 'res')
? ? }catch(e){
? ? ? ? console.log(e, 'e')
? ? }
}
const generator = foo()
const result = generator.next()
console.log(result, 'result')
generator.next('bar')
generator.throw(new Error('Generator Error'))
//管理異步流程 體驗Generator 函數(shù)異步方案
function *main(){
? ? try{
? ? ? ? const users = yield promise
? ? ? ? console.log('users', users)
? ? ? ? const posts = yield Promise.resolve(200)
? ? ? ? console.log(posts, 'posts')
? ? }catch(e){
? ? ? ? console.log(e)
? ? }
}
const g = main()
const result = g.next()
result.value.then(data => {
? ? const result2 = g.next(data)
? ? if(result2.done) return
? ? result2.value.then(data => {
? ? ? ? g.next(data)
? ? })
})
//遞歸執(zhí)行Generator函數(shù)
const g = main()
function handleResult (result){
? ? if(result.done) return
? ? result.value.then(data => {
? ? ? ? handleResult(g.next(data))
? ? }, error => {
? ? ? ? g.throw(error)
? ? })
}
handleResult(g.next())
function co(generator){
? ? const g = generator()
? ? function handleResult (result){
? ? ? ? if(result.done) return
? ? ? ? result.value.then(data => {
? ? ? ? ? ? handleResult(g.next(data))
? ? ? ? }, error => {
? ? ? ? ? ? g.throw(error)
? ? ? ? })
? ? }
? ? handleResult(g.next())
}
co(main)
#### Async/ Await 語法糖 語言層面的異步編程標準
async function mainSync(){
? ? try{
? ? ? ? const users = await promise
? ? ? ? console.log('users', users)
? ? ? ? const posts = await Promise.resolve(200)
? ? ? ? console.log(posts, 'posts')
? ? }catch(e){
? ? ? ? console.log(e)
? ? }
}
const mains = mainSync()
mains.then(()=>{
? ? console.log('all completed')
})