AsyncCallback AsyncCallback 非同步回撥委託
AsyncCallback 非同步回撥委託
AsyncCallback
意義:
非同步操作完成時呼叫的方法
語法1:
構造非同步回撥物件
AsyncCallback 非同步回撥物件名asyncCallback = new AsyncCallback(非同步操作完成時呼叫的方法MyAsyncCallback);
語法2:
定義委託,並進行非同步呼叫,非同步呼叫完成後自動觸發
委託型別Action fn委託名 = Run委託定義;
委託名fn.BeginInvoke(非同步回撥物件名asyncCallback );
示例:
using System; namespace Examples.AdvancedProgramming.AsynchronousOperations { public class UseDelegateForAsyncCallback { delegate string MethodDelegate(int iCallTime); public static void Main() { MethodDelegate dlgt = (m)=> { return "你輸入的數字是"+m; }; AsyncCallback asyncCallback = new AsyncCallback(MyAsyncCallback); Action fn = Run; fn.BeginInvoke(asyncCallback,null); } private static void MyAsyncCallback(IAsyncResult ar) { Console.WriteLine("非同步呼叫"); Console.ReadLine(); } public static void Run() { } } } /// 控制檯輸出結果: /// 你輸入的數字是:5 /// 非同步呼叫
JS非同步程式設計
JS三座大山:原型原型鏈、作用域閉包、同步非同步。
之前有寫過自己對閉包的理解,今天來總結一下JS中的非同步。
思考(案例來自stackoverflow):
function foo(){
var result; $ajax({ url:'...', success:function(response){ result=response; //return response;//tried this one as well } }); return result; } var result=foo();
初學非同步的時候,這裡是很容易錯的地方,你想要獲取從伺服器端返回的資料,結果卻一直undefined。
分析:
JavaScript是單執行緒語言,但是js中有很多工耗時比較長,比如ajax請求,如果都按照順序進行,往往會出現瀏覽器無響應的情況,所以就需要非同步的形式。JS中所有的任務可以分為兩種:同步任務和非同步任務。
同步任務:在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
非同步任務:不進入主執行緒,而進入任務佇列中的任務,只有任務佇列通知主執行緒,某個非同步任務可以執行了,這個任務才會進入主執行緒執行。
事件迴圈(Event Loop):只有執行棧中的所有同步任務都執行完畢,系統才會讀取任務佇列,看看裡面的非同步任務哪些可以執行,然後那些對應的非同步任務,結束等待狀態,進入執行棧,開始執行。
非同步的解決方案:
下面我們嘗試將上面程式碼改正一下,幾種方法如下:
1.callback
function foo(callback){//定義函式的時候將另一個函式(回撥函式)作為引數傳入定義的函式中。 $ajax({ //... success:callback//非同步操作執行完畢後,再執行該回調函式,確保回撥在非同步操作之後執行。 }); } function myCallback(result){ //... } foo(myCallback);
回撥函式本身是我們約定俗成的一種叫法,我們定義它,但是並不會自己去執行它,它最終被其他人執行了。
優點:比較容易理解;
缺點:1.高耦合,維護困難,回撥地獄;2.每個任務只能指定一個回撥函式;3.如果幾個非同步操作之間並沒有順序之分,同樣也要等待上一個操作執行結束再進行下一個操作。下圖回撥地獄(圖片來自於新浪微博(@ruanyf)):
2.Promise
function ajax(url){
return new Promise(function(resolve,reject){ var xhr=new XMLHttpRequest(); xhr.onload=function(){ resolve(this.responseText); }; xhr.onerror=reject; xhr.open('GET',url); xhr.send(); }); } ajax('/echo/json') .then(function(result){...}) .then(function(){...}) .catch(function(){...});
ES6給我們提供了一個原生的建構函式Promise,Promise代表了一個非同步操作,可以將非同步物件和回撥函式脫離開來,通過.then方法在這個非同步操作上繫結回撥函式,Promise可以讓我們通過鏈式呼叫的方法去解決回撥巢狀的問題,而且由於promise.all這樣的方法存在,可以讓同時執行多個操作變得簡單。
promise物件存在三種狀態:
1)Fulfilled:成功狀態
2)Rejected:失敗狀態
3)Pending:既不是成功也不是失敗狀態,可以理解為進行中狀態
promise物件的兩個重要方法:resolve/reject
1)resolve方法可以使Promise物件的狀態改變為成功,同時傳遞一個引數用於後續成功後的操作。
2)reject方法可以將Promise物件的狀態改變為失敗,同時將錯誤資訊傳遞到後續錯誤處理的操作。
.then可以使用鏈式呼叫,原因在於:每一次執行該方法時總會返回一個Promise物件。
另外,在then的函式當中的返回值,可以作為後續操作的引數(例如:.then(return a).then(console.log(a+b)))
那麼問題來了,如果上面程式碼非同步操作丟擲錯誤,會怎麼樣?會呼叫catch方法指定的回撥函式,處理這個錯誤,而且then方法指定的回撥函式,如果執行中丟擲錯誤,也會被catch捕獲。Promise物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止,也就是說,錯誤總是會被下一個catch語句捕獲。
理解Promise用法的關鍵點:
1.then方法是Promise例項的方法,即Promise.prototype上的,它的作用是為Promise例項新增狀態改變時的回撥函式,這個方法的第一個引數是resolved狀態的回撥函式,第二個引數(可選)是rejected狀態的回撥函式。
2.鏈式中的第二個then開始,它們的resolve中的引數,是前一個then中resolve的return語句的返回值。
3.關於執行順序:Promise在例項化的時候就會執行,也就是如果Promise的例項化語句中函式console.log輸出語句,它會比then中的先執行。Promise.all中傳入的Promise物件的陣列(假設為p1、p2),即使p2的執行速度比p1快,Promise.all方法仍然會按照陣列中的順序將結果返回。
理解了上面這些方便寫原生的Promise,利用觀察者模式。後面補充。
Promise的缺點:
1.當處於未完成狀態時,無法確定目前處於哪一階段。
2.如果不設定回撥函式,Promise內部的錯誤不會反映到外部。
3.無法取消Promise,一旦新建它就會立即執行,無法中途取消。
3.async/await:
很多人說async/await是非同步程式設計的終極解決方案、
JavaScript 的 async/await 實現,離不開 Promise。
var superagent=require('superagent')
function delay(){ return new Promise(function(resolve,reject){ setTimeout({ resolve(42); },3000); }) } async function getAllBooks(){ var bookIDs=await superagent.get('/user/books'); await delay(1000); return await superagent.get('/books/ids='JSON.stringify(bookIDs)); } getAllBooks() .then(function(){});
上面的 delay() 沒有申明為 async。實際上,delay() 本身就是返回的 Promise 物件,加不加 async 結果都一樣。
只要在函式名之前加上async關鍵字,就表明這個函式內部有非同步操作。這個非同步操作返回一個Promise物件,前面用await關鍵字註明。函式執行的時候,一旦遇到await,就會先執行await後面的表示式中的內容(非同步),不再執行函式體後面的語句。等到非同步操作執行完畢後,再自動返回到函式體內,繼續執行函式體後面的語句。
async:定義非同步函式
1)自動把函式轉換為Promise
2)當呼叫非同步函式時,函式返回值會被resolve處理
3)非同步函式內部可以使用await
await:暫停非同步函式的執行
1)當使用在Promise前面時,await等待Promise完成,並返回Promise的結果
2)await只能和Promise一起使用,不能和callback一起使用
3)await只能用在async函式中
async/await並不會取代promise,因為async/await底層依然使用promise。
async function getABC(){ let A = await getValueA(); // getValueA 花費 2 秒 let B = await getValueB(); // getValueA 花費 4 秒 let C = await getValueC(); // getValueA 花費 3 秒 return A*B*C }
每次遇到 await 關鍵字時,Promise 都會停下在,一直到執行結束,所以總共花費是 2+4+3 = 9 秒。await 把非同步變成了同步。
async function getABC() { // Promise.all() 允許同時執行所有的非同步函式 let results = await Promise.all([ getValueA, getValueB, getValueC ]); return results.reduce((total,value) => total * value); }
函式總耗時為 4 秒(getValueB 的耗時)。
Async 的價值在於用寫同步的方式寫非同步,1避免了阻塞,2必免寫回調
AsyncCallback
意義:
非同步操作完成時呼叫的方法
語法1:
構造非同步回撥物件
AsyncCallback 非同步回撥物件名asyncCallback = new AsyncCallback(非同步操作完成時呼叫的方法MyAsyncCallback);
語法2:
定義委託,並進行非同步呼叫,非同步呼叫完成後自動觸發
委託型別Action fn委託名 = Run委託定義;
委託名fn.BeginInvoke(非同步回撥物件名asyncCallback );
示例:
using System; namespace Examples.AdvancedProgramming.AsynchronousOperations { public class UseDelegateForAsyncCallback { delegate string MethodDelegate(int iCallTime); public static void Main() { MethodDelegate dlgt = (m)=> { return "你輸入的數字是"+m; }; AsyncCallback asyncCallback = new AsyncCallback(MyAsyncCallback); Action fn = Run; fn.BeginInvoke(asyncCallback,null); } private static void MyAsyncCallback(IAsyncResult ar) { Console.WriteLine("非同步呼叫"); Console.ReadLine(); } public static void Run() { } } } /// 控制檯輸出結果: /// 你輸入的數字是:5 /// 非同步呼叫
JS非同步程式設計
JS三座大山:原型原型鏈、作用域閉包、同步非同步。
之前有寫過自己對閉包的理解,今天來總結一下JS中的非同步。
思考(案例來自stackoverflow):
function foo(){
var result; $ajax({ url:'...', success:function(response){ result=response; //return response;//tried this one as well } }); return result; } var result=foo();
初學非同步的時候,這裡是很容易錯的地方,你想要獲取從伺服器端返回的資料,結果卻一直undefined。
分析:
JavaScript是單執行緒語言,但是js中有很多工耗時比較長,比如ajax請求,如果都按照順序進行,往往會出現瀏覽器無響應的情況,所以就需要非同步的形式。JS中所有的任務可以分為兩種:同步任務和非同步任務。
同步任務:在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;
非同步任務:不進入主執行緒,而進入任務佇列中的任務,只有任務佇列通知主執行緒,某個非同步任務可以執行了,這個任務才會進入主執行緒執行。
事件迴圈(Event Loop):只有執行棧中的所有同步任務都執行完畢,系統才會讀取任務佇列,看看裡面的非同步任務哪些可以執行,然後那些對應的非同步任務,結束等待狀態,進入執行棧,開始執行。
非同步的解決方案:
下面我們嘗試將上面程式碼改正一下,幾種方法如下:
1.callback
function foo(callback){//定義函式的時候將另一個函式(回撥函式)作為引數傳入定義的函式中。 $ajax({ //... success:callback//非同步操作執行完畢後,再執行該回調函式,確保回撥在非同步操作之後執行。 }); } function myCallback(result){ //... } foo(myCallback);
回撥函式本身是我們約定俗成的一種叫法,我們定義它,但是並不會自己去執行它,它最終被其他人執行了。
優點:比較容易理解;
缺點:1.高耦合,維護困難,回撥地獄;2.每個任務只能指定一個回撥函式;3.如果幾個非同步操作之間並沒有順序之分,同樣也要等待上一個操作執行結束再進行下一個操作。下圖回撥地獄(圖片來自於新浪微博(@ruanyf)):
2.Promise
function ajax(url){
return new Promise(function(resolve,reject){ var xhr=new XMLHttpRequest(); xhr.onload=function(){ resolve(this.responseText); }; xhr.onerror=reject; xhr.open('GET',url); xhr.send(); }); } ajax('/echo/json') .then(function(result){...}) .then(function(){...}) .catch(function(){...});
ES6給我們提供了一個原生的建構函式Promise,Promise代表了一個非同步操作,可以將非同步物件和回撥函式脫離開來,通過.then方法在這個非同步操作上繫結回撥函式,Promise可以讓我們通過鏈式呼叫的方法去解決回撥巢狀的問題,而且由於promise.all這樣的方法存在,可以讓同時執行多個操作變得簡單。
promise物件存在三種狀態:
1)Fulfilled:成功狀態
2)Rejected:失敗狀態
3)Pending:既不是成功也不是失敗狀態,可以理解為進行中狀態
promise物件的兩個重要方法:resolve/reject
1)resolve方法可以使Promise物件的狀態改變為成功,同時傳遞一個引數用於後續成功後的操作。
2)reject方法可以將Promise物件的狀態改變為失敗,同時將錯誤資訊傳遞到後續錯誤處理的操作。
.then可以使用鏈式呼叫,原因在於:每一次執行該方法時總會返回一個Promise物件。
另外,在then的函式當中的返回值,可以作為後續操作的引數(例如:.then(return a).then(console.log(a+b)))
那麼問題來了,如果上面程式碼非同步操作丟擲錯誤,會怎麼樣?會呼叫catch方法指定的回撥函式,處理這個錯誤,而且then方法指定的回撥函式,如果執行中丟擲錯誤,也會被catch捕獲。Promise物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止,也就是說,錯誤總是會被下一個catch語句捕獲。
理解Promise用法的關鍵點:
1.then方法是Promise例項的方法,即Promise.prototype上的,它的作用是為Promise例項新增狀態改變時的回撥函式,這個方法的第一個引數是resolved狀態的回撥函式,第二個引數(可選)是rejected狀態的回撥函式。
2.鏈式中的第二個then開始,它們的resolve中的引數,是前一個then中resolve的return語句的返回值。
3.關於執行順序:Promise在例項化的時候就會執行,也就是如果Promise的例項化語句中函式console.log輸出語句,它會比then中的先執行。Promise.all中傳入的Promise物件的陣列(假設為p1、p2),即使p2的執行速度比p1快,Promise.all方法仍然會按照陣列中的順序將結果返回。
理解了上面這些方便寫原生的Promise,利用觀察者模式。後面補充。
Promise的缺點:
1.當處於未完成狀態時,無法確定目前處於哪一階段。
2.如果不設定回撥函式,Promise內部的錯誤不會反映到外部。
3.無法取消Promise,一旦新建它就會立即執行,無法中途取消。
3.async/await:
很多人說async/await是非同步程式設計的終極解決方案、
JavaScript 的 async/await 實現,離不開 Promise。
var superagent=require('superagent')
function delay(){ return new Promise(function(resolve,reject){ setTimeout({ resolve(42); },3000); }) } async function getAllBooks(){ var bookIDs=await superagent.get('/user/books'); await delay(1000); return await superagent.get('/books/ids='JSON.stringify(bookIDs)); } getAllBooks() .then(function(){});
上面的 delay() 沒有申明為 async。實際上,delay() 本身就是返回的 Promise 物件,加不加 async 結果都一樣。
只要在函式名之前加上async關鍵字,就表明這個函式內部有非同步操作。這個非同步操作返回一個Promise物件,前面用await關鍵字註明。函式執行的時候,一旦遇到await,就會先執行await後面的表示式中的內容(非同步),不再執行函式體後面的語句。等到非同步操作執行完畢後,再自動返回到函式體內,繼續執行函式體後面的語句。
async:定義非同步函式
1)自動把函式轉換為Promise
2)當呼叫非同步函式時,函式返回值會被resolve處理
3)非同步函式內部可以使用await
await:暫停非同步函式的執行
1)當使用在Promise前面時,await等待Promise完成,並返回Promise的結果
2)await只能和Promise一起使用,不能和callback一起使用
3)await只能用在async函式中
async/await並不會取代promise,因為async/await底層依然使用promise。
async function getABC(){ let A = await getValueA(); // getValueA 花費 2 秒 let B = await getValueB(); // getValueA 花費 4 秒 let C = await getValueC(); // getValueA 花費 3 秒 return A*B*C }
每次遇到 await 關鍵字時,Promise 都會停下在,一直到執行結束,所以總共花費是 2+4+3 = 9 秒。await 把非同步變成了同步。
async function getABC() { // Promise.all() 允許同時執行所有的非同步函式 let results = await Promise.all([ getValueA, getValueB, getValueC ]); return results.reduce((total,value) => total * value); }
函式總耗時為 4 秒(getValueB 的耗時)。
Async 的價值在於用寫同步的方式寫非同步,1避免了阻塞,2必免寫回調