中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于javascript的異步編程實例詳解

發布時間:2020-10-07 19:07:38 來源:腳本之家 閱讀:165 作者:布瑞澤的童話 欄目:web開發

本文實例講述了基于javascript的異步編程。分享給大家供大家參考,具體如下:

異步函數這個術語有點名不副實,調用一個函數后,程序只在該函數返回后才能繼續。JavaScript程序員如果稱一個函數為異步的,其意思就是這個函數會導致將來再運行另一個函數,后者取自于事件隊列。如果后面這個函數是作為參數傳遞給前者的,則稱其為回調函數。

callback

回調函數是異步編程最基本的方式。

采用這種方式,我們把同步操作變成了異步操作,主函數不會堵塞程序運行,相當于先執行程序的主要邏輯,將耗時的操作推遲執行。

回調函數的優點是簡單、容易理解和部署,缺點是不利于代碼的閱讀和維護。

我們定義一個delay函數,它是異步的,也就是說它會拖延指定函數的執行,從而使現在正在執行的程序繼續執行。delay函數如下:

function delay(time, callback) {
 setTimeout(function () {
 callback("Slept for "+time);
 }, time);
}

那么如果我要delay兩次呢?

delay(1000, function(msg) {
 console.log(msg);
 delay(1200, function (msg) {
 console.log(msg);
 }
})
//...waits 1000ms
// > "Slept for 1000"
//...waits another 1200ms
// > "Slept for 1200"

只有這樣我們才能夠確保兩個delay一個接一個的執行。如果層次多了呢?就會形成回調地獄。當異步任務很多時,維護大量的callback將是一場災難。

Promise

Promise是一個被納入ES6中的規范,各大框架也早已實現相關方法。

Promise可以理解為一個承諾,如果A調用B,B返回一個承諾給A,然后A就可以在寫計劃的時候這么寫,當B返回結果的時候,A就執行方案1,如果B沒有返回A要的結果,A就執行方案2。這樣一來,所有的潛在風險就都在A的可控范圍之內了。

我們看看ES6中promise的用法示例:

'use strict';
var promiseCount = 0; 
function testPromise() {
 var thisPromiseCount = ++promiseCount;
 var log = document.getElementById('log');
 log.insertAdjacentHTML('beforeend', thisPromiseCount +') Started (<small>Sync code started</small>)<br/>');
 // 我們創建一個新的Promise,期望3秒后得到結果
 var p1 = new Promise(
 //當Promise解決或拒絕時該函數被調用
 function(resolve, reject) {
  log.insertAdjacentHTML('beforeend', thisPromiseCount +') Promise started (<small>Async code started</small>)<br/>');
  // 創建異步操作
  window.setTimeout(
  function() {
   // 滿足Promise
   resolve(thisPromiseCount);
  }, Math.random() * 2000 + 1000);
  });
  // 當Promise被滿足時執行
  p1.then(
  // 輸出信息和值
  function(val) {
   log.insertAdjacentHTML('beforeend', val +') Promise fulfilled (<small>Async code terminated</small>)<br/>');
  })
  .catch(
  // 當Promise被拒絕時執行
   function(reason) {
   console.log('Handle rejected promise ('+reason+') here.');
   });
  log.insertAdjacentHTML('beforeend', thisPromiseCount +') Promise made (<small>Sync code terminated</small>)<br/>');
}

快速連續執行函數,得到結果:

基于javascript的異步編程實例詳解

說明1,2異步操作后正常順序執行完畢。更多Promise的詳細用法請參考:MDN

很多框架也提供了Promise相關方法,這里我們以jQuery為例。

$("button").bind( "click", function() {
 $("p").append( "Started...");
 $("div").each(function( i ) {
 $( this ).fadeIn().fadeOut( 1000 * (i+1) );
 });
 $( "div" ).promise().done(function() {
 $( "p" ).append( " Finished! " );
 });
});

可以看到,當$("div")的所有任務執行完畢后,就會調用最后的done操作。

Jquery中的Promise也可以代表多種結果,出現不同結果時會分別調用相應的回調。我們以ajax調用為例。1.5之前版本中,代碼必須寫成這樣:

$.get('/getdata',{
 success:onSuccess,
 failure:onFailure,
 always:onAlways
});

而1.5+版本引入了Promise對象后。可以寫成如下形式:

var promise = $.get('/getdata');
promise.done(onSuccess);
promise.fail(onFailure);
promise.always(onAlways);

那么這種變化有什么好處呢?為什么非要在觸發ajax調用之后再附加回調呢?如果ajax要實現很多效果,比如觸發動畫、插入html、鎖定輸入等,那么僅僅由負責發出請求那部分應用代碼來處理所有這些效果,顯然很蠢。只傳遞Promise就顯得很優雅。

更多詳細請參考:jquery

Promise雖然是很優雅,但是也只是解決了回調地獄的問題,真正簡化javascript異步編程的還是Generator

Generator

生成器是ES6中的語法。

何為生成器?讓我們先看看以下代碼:

function* quips(name) {
 yield "hello " + name + "!";
 yield "i hope you are enjoying the blog posts";
 if (name.startsWith("X")) {
 yield "it's cool how your name starts with X, " + name;
 }
 yield "see you later!";
}

你沒有看錯,這就是javascript代碼。是不是和你曾經認識的javascript不太一樣。這個函數就叫做生成器函數。生成器函數看起來和普通的函數是不是有點相像呢?

它們的區別如下:

一般的函數以function開頭,而生成器函數以function* 開頭。

生成器函數中有一個特殊關鍵字就是yield,作用就是暫停函數。配合next方法來調用可以達到一步一步的執行函數的目的。

我們看看next方法的使用:

> var iter = quips("jorendorff");
 [object Generator]
> iter.next()
 { value: "hello jorendorff!", done: false }
> iter.next()
 { value: "i hope you are enjoying the blog posts", done: false }
> iter.next()
 { value: "see you later!", done: false }
> iter.next()
 { value: undefined, done: true }

可以看到,每一次next方法后,生成器函數就執行到下一個yield位置處。

下面我們講解如何通過生成器函數來取代回調函數。我們還是以一開始的多次延遲delay為例。

首先,我們需要定義一個生成器:

function* myDelayedMessages() {
 /* delay 1000 ms and print the result */
 /* delay 1200 ms and print the result */
}

然后我們需要設置delay時間來執行指定操作,我們現在暫定為空函數。

function* myDelayedMessages() {
 console.log(delay(1000, function(){}));
 console.log(delay(1200, function(){}));
}

然后我們使用yield關鍵字:

function* myDelayedMessages() {
 console.log(yield delay(1000, function(){}));
 console.log(yield delay(1200, function(){}));
}

然后我們就需要指定一個函數run來調用生成器函數的next方法,并且將空函數改為參數resume:

function run(generatorFunction) {
 var generatorItr = generatorFunction(resume);
 function resume(callbackValue) {
 generatorItr.next(callbackValue);
 }
 generatorItr.next()
}

最后執行代碼如下:

run(function* myDelayedMessages(resume) {
 console.log(yield delay(1000, resume));
 console.log(yield delay(1200, resume));
})
//...waits 1000ms
// > "Slept for 1000"
//...waits 1200ms
// > "Slept for 1200"

這樣就完美的避免了回調地獄噢!

更多關于JavaScript相關內容可查看本站專題:《javascript面向對象入門教程》、《JavaScript中json操作技巧總結》、《JavaScript切換特效與技巧總結》、《JavaScript查找算法技巧總結》、《JavaScript動畫特效與技巧匯總》、《JavaScript錯誤與調試技巧總結》、《JavaScript數據結構與算法技巧總結》、《JavaScript遍歷算法與技巧總結》及《JavaScript數學運算用法總結》

希望本文所述對大家JavaScript程序設計有所幫助。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永泰县| 新疆| 醴陵市| 普陀区| 西藏| 西畴县| 芮城县| 台州市| 同江市| 巴中市| 阿尔山市| 松潘县| 辽中县| 南澳县| 阿克陶县| 阳东县| 穆棱市| 浏阳市| 全州县| 彭阳县| 杂多县| 兴义市| 晋州市| 兖州市| 治县。| 义乌市| 镇宁| 定结县| 清丰县| 定兴县| 泾阳县| 桃源县| 永泰县| 九寨沟县| 鹤峰县| 澜沧| 江山市| 昭苏县| 永春县| 芮城县| 芒康县|