技術(shù)頻道導(dǎo)航
HTML/CSS
.NET技術(shù)
IIS技術(shù)
PHP技術(shù)
Js/JQuery
Photoshop
Fireworks
服務(wù)器技術(shù)
操作系統(tǒng)
網(wǎng)站運(yùn)營(yíng)

贊助商

分類(lèi)目錄

贊助商

最新文章

搜索

JavaScript回調(diào)函數(shù):同步回調(diào)與異步回調(diào)

作者:admin    時(shí)間:2022-6-27 15:51:8    瀏覽:

JavaScript 回調(diào)函數(shù),是將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),然后可以在另一個(gè)函數(shù)中調(diào)用該函數(shù)?;卣{(diào)有很多好處,它們開(kāi)辟了很多編程可能性?;卣{(diào)方式也不是唯一的,我們可以同步回調(diào),也可以異步回調(diào),這就是我今天要說(shuō)的內(nèi)容。

同步回調(diào)

許多人第一次接觸回調(diào)是在他們了解到可以為同一個(gè)排序算法提供不同的比較函數(shù)時(shí)。例如,當(dāng)使用Array.prototype.sort()方法對(duì)整數(shù)數(shù)組進(jìn)行排序時(shí),可選參數(shù)是比較函數(shù)compareFn。

let arr1 = [22, 25, 55, 66, 23, 15, 1, 12]
arr1.sort() // arr1按升序排序
// arr1 變成 [1, 12, 15, 22, 23, 25, 55, 66]
let arr2 = […arr1] // 復(fù)制 arr1 到 arr2
arr2.sort((e1, e2)=> e2-e1) // arr2 按降序排序
// arr2 變成 [66, 55, 25, 23, 22, 15, 12, 1 ]
// (e1, e2)=> e2-e1 是比較函數(shù)

這種回調(diào)在大多數(shù)編程語(yǔ)言中都有,達(dá)到多態(tài)算法的效果。

上面說(shuō)明了同步回調(diào)是如何工作的。同步回調(diào)在使用它們的高階函數(shù)內(nèi)部執(zhí)行。當(dāng)高階函數(shù)完成執(zhí)行時(shí),其回調(diào)參數(shù)的執(zhí)行也完成。由于高階函數(shù)必須等待同步回調(diào)執(zhí)行完成,所以同步回調(diào)也稱(chēng)為阻塞回調(diào)——回調(diào)的執(zhí)行會(huì)阻塞調(diào)用者函數(shù)的執(zhí)行。

JavaScript 中同步回調(diào)的一些其他示例是用于迭代數(shù)組的方法:forEach、map、filter、reduce、someevery等。

let arr = [1,2,3,4,5] 
let arrDoubled = arr.map(e=>e+e) 
console.log(arrDoubled) // 輸出 [ 2, 4, 6, 8, 10 ]

異步回調(diào)

如果說(shuō)同步回調(diào)是實(shí)現(xiàn)更大編程靈活性的方法,那么異步回調(diào)是實(shí)現(xiàn)更高性能和用戶體驗(yàn)的方法。

異步回調(diào)的強(qiáng)大之處在于 JavaScript 獨(dú)特的運(yùn)行時(shí)模型。JavaScript 是一種單線程語(yǔ)言,也就是說(shuō) JavaScript 的執(zhí)行引擎只有一個(gè)調(diào)用棧。

那么異步執(zhí)行是如何實(shí)現(xiàn)的呢?

神奇之處在于 JavaScript 運(yùn)行時(shí)環(huán)境的 API 處理程序。對(duì)于 Web 瀏覽器,API 是 Web API;對(duì)于 Node.js,API 是 I/O API。執(zhí)行異步回調(diào)的任務(wù)被放入回調(diào)隊(duì)列。

在調(diào)用堆棧中的現(xiàn)有代碼運(yùn)行完成后,事件循環(huán)(作為 JavaScript 引擎的一部分的進(jìn)程)將回調(diào)隊(duì)列中的回調(diào)帶入執(zhí)行。

一旦執(zhí)行引擎運(yùn)行回調(diào),它會(huì)在下一個(gè)回調(diào)開(kāi)始運(yùn)行之前再次運(yùn)行到完成(直到調(diào)用堆棧為空)。調(diào)用堆棧上的代碼的這種運(yùn)行到完成一直持續(xù)到隊(duì)列中的所有回調(diào)都被執(zhí)行為止。

異步方面來(lái)自這樣一個(gè)事實(shí),即回調(diào)不是在高階函數(shù)中立即執(zhí)行,而是放在回調(diào)隊(duì)列中等待輪到它在調(diào)用堆棧上運(yùn)行。

高階函數(shù)是派發(fā)回調(diào)任務(wù)的函數(shù),而不是運(yùn)行它的函數(shù)。

使用異步回調(diào)最普遍的例子是使用setTimeOut方法。

console.log("setTimeout 之前") 
setTimeout( 
    ()=>{ console.log("這里是2秒后的結(jié)果") }, 
    2000 

console.log("setTimeout 之后")

第一個(gè)參數(shù)是回調(diào)函數(shù),第二個(gè)參數(shù)是等待的時(shí)間,以毫秒為單位。setTimeout無(wú)需等待回調(diào)完成即可返回。

以下是輸出的樣子:

setTimeout 之前
setTimeout 之后
這里是2秒后的結(jié)果

異步回調(diào)機(jī)制的好處

異步回調(diào)機(jī)制的好處是所有同步代碼都不會(huì)被異步事件阻塞。異步事件(例如對(duì)遠(yuǎn)程服務(wù)器的 AJAX 請(qǐng)求)可能需要一些時(shí)間才能運(yùn)行。通過(guò)異步回調(diào),Web 應(yīng)用程序可以更流暢地運(yùn)行且響應(yīng)速度更快。

示例:同步回調(diào)轉(zhuǎn)換為異步回調(diào)

同步回調(diào)

console.log('start');

function getGreeting(name, cb) {
  cb(`Hello ${name}`);
}

console.log('before getGreeting');

getGreeting('WebKaka', (greeting) => {
  console.log(greeting);
});

console.log('end');

輸出

start
before getGreeting
Hello WebKaka
end

該程序從頂部開(kāi)始,并在到達(dá)底部時(shí)順序執(zhí)行每一行。

異步回調(diào)

我們可以把上面的例子改為異步回調(diào)。

console.log('start');

function getGreetingAsync(name, cb) {
   setTimeout(() => {
     cb(`Hello ${name}`);
   }, 0);
}

console.log('before getGreetingAsync');

getGreetingAsync('WebKaka', (greeting) => {
  console.log(greeting);
});

console.log('end');

輸出

start
before getGreetingAsync
end
Hello WebKaka

通過(guò)添加 setTimeout,我們將回調(diào)函數(shù)的執(zhí)行推遲到稍后的時(shí)間點(diǎn)。回調(diào)函數(shù)只有在程序從上到下執(zhí)行完代碼后才會(huì)運(yùn)行(即使延遲為0ms)。

同步回調(diào)和異步回調(diào)之間的主要區(qū)別在于同步回調(diào)立即執(zhí)行,而異步回調(diào)的執(zhí)行推遲到稍后的時(shí)間點(diǎn)。

如何判斷回調(diào)是同步還是異步?

回調(diào)是同步執(zhí)行還是異步執(zhí)行取決于調(diào)用它的函數(shù)。如果函數(shù)是異步的,那么回調(diào)也是異步的。

異步函數(shù)通常是執(zhí)行網(wǎng)絡(luò)請(qǐng)求、等待 I/O 操作(如鼠標(biāo)單擊)、與文件系統(tǒng)交互或向數(shù)據(jù)庫(kù)發(fā)送查詢的函數(shù)。這些函數(shù)的共同點(diǎn)是它們與當(dāng)前程序之外的東西進(jìn)行交互,并且你的應(yīng)用程序一直等待直到響應(yīng)返回。

相反,同步回調(diào)在程序的當(dāng)前上下文中執(zhí)行,與外界沒(méi)有交互。你會(huì)在函數(shù)式編程中找到同步回調(diào),例如,為集合中的每個(gè)項(xiàng)目調(diào)用回調(diào)(例如.filter()、.map()、.reduce()等)。JavaScript 語(yǔ)言中的大多數(shù)原型方法都是同步的。

如果你不確定一個(gè)回調(diào)函數(shù)是同步執(zhí)行還是異步執(zhí)行,你可以在回調(diào)內(nèi)部和之后添加console.log語(yǔ)句,看看哪個(gè)先打印。

總結(jié)

本文介紹了JavaScript回調(diào)函數(shù):同步回調(diào)與異步回調(diào)。無(wú)論是同步回調(diào)還是異步回調(diào),都有各自的好處,在使用時(shí)需根據(jù)具體情況而選擇采用何種編程方式。

相關(guān)文章

標(biāo)簽: 回調(diào)函數(shù)  callback  
x
  • 站長(zhǎng)推薦
/* 左側(cè)顯示文章內(nèi)容目錄 */