問題圖示以下javascript
按鈕A按了以後,ajax請求的數據顯示在input type=text框裏,B按鈕也是。前端
問題就是若是先按A,此時ajax發出去了,可是數據還沒返回來, 咱們等不及了,立刻按B按鈕,結果此時A按鈕請求的數據先回來,這就尷尬了,按的b按鈕,結果先顯示A按鈕返回的數據,怎麼解決?java
這個問題的解釋在我以前寫的一篇文章,其中的第二題就是解決方https://juejin.im/post/5a1810b56fb9a0452405854c,咱們今天把這個問題展開ajax
如下是一張解釋異步隊列的圖,以及文字說明(摘自阮一峯老師的博客)後端
(1)全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)。
(2)主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
(3)一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,因而結束等待狀態,進入執行棧,開始執行。
(4)主線程不斷重複上面的第三步。
複製代碼
這只是針對跟我同樣中級水平或偏下的人普及一下JS異步的運行原理。以後,咱們來看一個異步引起的問題代碼promise
var res = [];
function response(data) {
res.push( data );
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
問題來了,咱們假按期望的行爲是res[0] 中放調用"http://some.url.1" 的結果,res[1] 中放調用"http://some.url.2" 的結果,改怎麼辦呢? 解決辦法以下bash
var res = [];
function response(data) {
if (data.url == "http://some.url.1") {
res[0] = data;
}
else if (data.url == "http://some.url.2") {
res[1] = data;
}
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
上面這個場景用於多個併發函數共享DOM的問題,因此回調函數能夠改進成這樣的寫法併發
var res = [];
function response(data) {
if (data.url == "http://some.url.1") {
//執行操做的函數,把參數data傳入進去
callbackA(data)
}
else if (data.url == "http://some.url.2") {
//執行操做的函數,把參數data傳入進去
callbackB(data)
}
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
好了,咱們總結出一種處理併發共享DOM問題的解決方案,這個方案是我在一本叫《你不知道javascript 中卷》看到的,考官繼續說,不用這種方法,由於要依賴後端發的數據要包含data.url,也就是url這個屬性,怎樣不依賴後端,前端獨立解決這個問題呢? 在response上咱們作一下改動,設置一個全局變量異步
var status; //值是undefined
複製代碼
咱們在點擊A按鈕的時候, 讓status的值變爲A函數
status = "A";
複製代碼
咱們在點擊B按鈕的時候,讓status的值變爲B
status = "B";
複製代碼
也就是resopnse改爲這樣:
function response(data) {
var status;
if(status = "A") {
// 點擊A按鈕status就變爲「A」,因此不會執行按鈕B的回調函數
執行 callbackA() A按鈕的回調函數
}else if(status = "B"){
// 點擊B按鈕status就變爲「B」,因此不會執行按鈕A的回調函數
執行 callbackB() B按鈕的回調函數
}
}
複製代碼
這樣就解決了點A只顯示A的數據,點B只顯示B的數據的問題。
在這裏咱們繼續延伸這個話題, 請看如下場景
var a,b;
function foo(x) {
a = x * 2;
baz();
}
function bar(y) {
b = y * 2;
baz()
}
function baz() {
console.log(a+b)
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
咱們的目的是等a,b都異步請求回來才運行baz,解決辦法以下
var a,b;
function foo(x) {
a = x * 2;
if(a && b) {
baz();
}
}
function bar(y) {
b = y * 2;
if(a && b) {
baz();
}
}
function baz() {
console.log(a+b)
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
接着,咱們再換一個場景, 請看如下代碼
var a;
function foo(x) {
a = x * 2
baz();
}
function bar(x) {
a = x / 2;
baz();
}
function baz() {
console.log(a)
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
a的值會改變兩次,需求是隻讓a變一次,也就是第一次改變,第二次就不改變了
var a;
function foo(x) {
if(!a) {
a = x * 2;
baz();
}
}
function bar(y) {
if(!a) {
a = x / 2;
baz();
}
}
function baz() {
console.log(a)
}
// ajax(..)是某個庫中提供的某個Ajax函數
ajax( "http://some.url.1", response );
ajax( "http://some.url.2", response );
複製代碼
好了,下面我要寫一篇用promise解決異步問題的隨筆(曾經看了一篇關於原生實現promise的文章,到時候也會簡單介紹下一個簡單的,但不是徹底體的promise實現代碼,只是爲了你們更容易理解promise實現的內部大體原理),題目以下,須要20張圖片,每次發出10個異步請求,請求10張圖片,因此一共要請求兩次,並且要求每次請求的10張圖片是按順序接收的,好比第一次發的請求是請求趙麗穎的圖片,第二次發的請求是請求張三瘋的圖片,要求接收的順序也是趙麗穎圖片,張三瘋圖片 ...以此類推。