在js中,任務(wù)可分為兩種,同步任務(wù)和異步任務(wù)。
(1) 同步任務(wù)
又叫 非耗時(shí)任務(wù),指的是在主線程排隊(duì)執(zhí)行的那些任務(wù)
只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù)
(2) 異步任務(wù)
又叫 耗時(shí)任務(wù),異步任務(wù)由JavaScript委托給宿主環(huán)境進(jìn)行執(zhí)行
當(dāng)異步任務(wù)執(zhí)行完成后,會(huì)通知JavaScript主線程執(zhí)行異步任務(wù)的回調(diào)函數(shù)
當(dāng)我們打開網(wǎng)站時(shí),像圖片的加載,音樂的加載,其實(shí)就是一個(gè)異步任務(wù)
現(xiàn)有a、b和c三個(gè)任務(wù),如果其為同步任務(wù),可以很簡(jiǎn)單地順序執(zhí)行,但如果其為異步任務(wù),該如何順序執(zhí)行呢?
一、回調(diào)函數(shù)
function thing(thingName, callback) {
setTimeout(() => {
console.log(`執(zhí)行${
thingName}任務(wù)`)
typeof callback === 'function' && callback()
}, 1000)
}
// 執(zhí)行a任務(wù)
// 執(zhí)行b任務(wù)
// 執(zhí)行c任務(wù)
thing('a', () => {
thing('b', () => {
thing('c')
})
})
優(yōu)點(diǎn):簡(jiǎn)單、方便、實(shí)用
缺點(diǎn):回調(diào)函數(shù)層層嵌套,不易于閱讀和維護(hù),形成回調(diào)地獄。
二、promise
1. 使用方式
基本使用
new Promise ((resolve, reject) => {
// 執(zhí)行代碼
}).then(() => {
// 期約兌現(xiàn)
}).catch(() => {
// 期約拒絕
})
詳細(xì)使用戳這里
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise#%E7%A4%BA%E4%BE%8B
2. 異步任務(wù)順序執(zhí)行
function thing(thingName) {
return new Promise(resolve => {
setTimeout(() => {
console.log(`執(zhí)行${
thingName}任務(wù)`)
resolve()
}, 1000)
})
}
// 執(zhí)行a任務(wù)
// 執(zhí)行b任務(wù)
// 執(zhí)行c任務(wù)
thing('a')
.then(() => thing('b'))
.then(() => thing('c'))
3. 實(shí)現(xiàn)原理
那么如何實(shí)現(xiàn)一個(gè)promise呢?實(shí)現(xiàn)promise之前,先分析下promise的結(jié)構(gòu)
-
promise存在三個(gè)狀態(tài),pending 待定, fulfilled 兌現(xiàn), rejected 拒絕,因此需要
(1)定義三個(gè)常量 PENDING、FULFILLED、REJECTED 對(duì)應(yīng)三種狀態(tài)
(2)定義 status 表示期約當(dāng)前狀態(tài)
(3)定義 value 表示已兌現(xiàn)期約值、定義 reason 表示已拒絕期約原因
-
在調(diào)用promise的實(shí)例函數(shù)時(shí),我們傳入了一個(gè)執(zhí)行器,執(zhí)行器接收兩個(gè)函數(shù),其作用分別為將待定期約轉(zhuǎn)化為已兌現(xiàn)期約與已拒絕期約。因此需要定義兩個(gè)函數(shù) resolve 和 reject
-
已兌現(xiàn)期約、已拒絕期約處理函數(shù) then
已拒絕期約處理函數(shù) catch
最終執(zhí)行函數(shù) finally
-
靜態(tài)函數(shù) resolve、reject、 all 及 race 的實(shí)現(xiàn)
代碼實(shí)現(xiàn)基于以下鏈接調(diào)整
https://juejin.cn/post/6945319439772434469#heading-30
3.1 promise簡(jiǎn)易實(shí)現(xiàn)
// MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// 期約狀態(tài), 初始值為pending
status = PENDING
// 已兌現(xiàn)期約值
value = null
// 已拒絕期約原因
reason = null
constructor(executor){
executor(this.resolve, this.reject)
}
// 將待定期約轉(zhuǎn)化為已兌現(xiàn)期約
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
}
}
// 將待定期約轉(zhuǎn)化為已拒絕期約
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
}
}
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = MyPromise
同目錄下新建 test.js 文件用于測(cè)試
// test.js
// 引入我們的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise1 = new MyPromise((resolve, reject) => {
resolve('resolve')
})
const promise2 = new MyPromise((resolve, reject) => {
reject('reject')
})
promise1.then(value => {
console.log('promise1 then', value)
}, reason => {
console.log('promise1 catch', reason)
})
promise2.then(value => {
console.log('promise2 then', value)
}, reason => {
console.log('promise2 catch', reason)
})
// 執(zhí)行結(jié)果
// promise1 then resolve
// promise2 catch reject
3.2 加入異步邏輯
繼續(xù)測(cè)試,發(fā)現(xiàn)異步執(zhí)行resolve函數(shù)時(shí),會(huì)存在問題。因此,我們需對(duì)異步邏輯進(jìn)行處理。
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('resolve'), 0)
})
promise.then(value => {
console.log('promise then', value)
}, reason => {
console.log('promise catch', reason)
})
// 期望輸出 promise then resolve
// 實(shí)際無輸出
(1) 緩存兌現(xiàn)與拒絕回調(diào)
// 存儲(chǔ)兌現(xiàn)回調(diào)函數(shù)
onFulfilledCallback = null
// 存儲(chǔ)拒絕回調(diào)函數(shù)
onRejectedCallback = null
(2) then 方法中新增待定期約處理
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.onFulfilledCallback = onFulfilled
this.onRejectedCallback = onRejected
}
}
(3) resolve 與 reject 中調(diào)用回調(diào)函數(shù)
// 將待定期約轉(zhuǎn)化為已兌現(xiàn)期約
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 兌現(xiàn)回調(diào)函數(shù)存在則執(zhí)行
this.onFulfilledCallback && this.onFulfilledCallback(value)
}
}
// 將待定期約轉(zhuǎn)化為已拒絕期約
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 拒絕回調(diào)函數(shù)存在則執(zhí)行
this.onRejectedCallback && this.onRejectedCallback(reason)
}
}
使用以下代碼再次驗(yàn)證,異步問題解決。
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('resolve'), 0)
})
promise.then(value => {
console.log('promise then', value)
}, reason => {
console.log('promise catch', reason)
})
// 執(zhí)行結(jié)果: promise then resolve
3.3 實(shí)現(xiàn) then 方法多次調(diào)用添加多個(gè)處理函數(shù)
Promise支持添加多個(gè)處理函數(shù),來測(cè)試下自定義Promise是否滿足。
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
promise.then(value => {
console.log(1)
console.log('resolve', value)
})
promise.then(value => {
console.log(2)
console.log('resolve', value)
})
promise.then(value => {
console.log(3)
console.log('resolve', value)
})
// 3
// resolve success
經(jīng)測(cè)試,自定義Promise并不能添加多個(gè)處理函數(shù),繼續(xù)修改。
(1) 新增兌現(xiàn)與拒絕回調(diào)數(shù)組
// 存儲(chǔ)兌現(xiàn)回調(diào)函數(shù)數(shù)組
onFulfilledCallbacks = []
// 存儲(chǔ)拒絕回調(diào)函數(shù)數(shù)組
onRejectedCallbacks = []
(2) then方法中存儲(chǔ)回調(diào)文章來源:http://www.zghlxwxcb.cn/news/detail-489142.html
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
}
(3) resolve 與 reject 中循環(huán)調(diào)用回調(diào)函數(shù)文章來源地址http://www.zghlxwxcb.cn/news/detail-489142.html
// 將待定期約轉(zhuǎn)化為已兌現(xiàn)期約
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 兌現(xiàn)回調(diào)函數(shù)存在則執(zhí)行
while (this.onFulfilledCallbacks.length) {
到了這里,關(guān)于js中如何順序執(zhí)行異步任務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!