摘要:但是提出標準,允許腳本創建多個線程,但是子線程完全受主線程控制。只是將事件插入了任務隊列,必須等到當前代碼執行棧執行完,主線程才會去執行它指定的回調函數。之后全局上下文進入函數調用棧。
setTimeout 一、setTimeout 初現
定義:setTimeout() 方法用于在指定的毫秒數后調用函數或計算表達式。
語法:
setTimeout(code, milliseconds, param1, param2, ...) setTimeout(function, milliseconds, param1, param2, ...)
參數 | 描述 |
---|---|
code/function | 必需。要調用一個代碼串,也可以是一個函數 |
milliseconds | 可選。執行或調用 code/function 需要等待的時間,以毫秒計。默認為 0。 |
param1, param2, ... | 可選。 傳給執行函數的其他參數(IE9 及其更早版本不支持該參數)。 |
第一種
setTimeout(fn1, 1000); setTimeout(fn2, 2000); setTimeout(function fn3(){console.log(3);}, 3000); setTimeout(function (){console.log(4);}, 4000); function fn1(){ console.log(1); } var fn2 = function(){ console.log(2); } //輸出結果如下: // 分別延遲1,2,3,4秒之后輸出 1 2 3 4
第二種
setTimeout(fn1(), 1000); setTimeout(fn2(), 2000); setTimeout(function fn3(){console.log(3);}(), 3000); setTimeout(function (){console.log(4);}(), 4000); function fn1(){ console.log(1); } var fn2 = function(){ console.log(2); } //輸出結果如下: //直接輸出 1 2 3 4 ,沒有延遲
按照定義:setTimeout() 方法用于在指定的毫秒數后調用函數或計算表達式。第一種方法在指定毫秒數之后執行,第二種方法沒有在指定毫秒數后執行,而是立刻執行。所以我個人將其分成正規軍setTimeout和雜牌軍setTimeout,方便后面記憶。
正規軍我們在后面詳細講,現在先了解下雜牌軍:
由于setTimeout()的第一個參數是**直接可執行的代碼**,所以它沒有任何延遲效果,如下:
setTimeout(console.log(1), 1000); //輸出結果如下: //直接輸出 1 ,沒有延遲三、setTimeout 再遇
setTimeout(function(a,b){ console.log(a+b); },1000,4,5); //輸出結果如下: //9
從第三個參數開始,依次用來表示第一個參數(回調函數)傳入的參數
一些古老的瀏覽器是不支持,可以用bind或apply方法來解決,如下:
setTimeout(function(a,b){ console.log(a+b); }.bind(this,4,5),1000); //輸出結果如下: //9
第一個參數表示將原函數的this綁定全局作用域,第二個參數開始是要傳入原函數的參數
當調用綁定函數時,綁定函數會以創建它時傳入bind()方法的第一個參數作為 this
對于setTimeout()的this問題,網上有很多的文章,我就不班門弄斧了,后面若總結的夠到位了就寫一篇文章介紹下。
console.log(1); setTimeout(function (){ console.log(2); },3000); console.log(3); //輸出結果如下: //1 3 2
console.log(1); setTimeout(function (){ console.log(2); },0); console.log(3); //輸出結果如下: //1 3 2
這里有些同學可能會疑惑,第一段代碼延遲三秒之后執行輸出1,3,2可以理解,但是第二段代碼延遲0秒執行為什么也是會輸出1,3,2呢?
這里就需要提到“任務隊列”這個概念了,由于JavaScript是一種單線程的語言,也就是說同一時間只能做一件事情。但是HTML5提出Web Worker標準,允許JavaScript腳本創建多個線程,但是子線程完全受主線程控制。
單線程意味著,所有的任務需要排隊,前一個任務結束,才會執行后一個任務。如果前一個任務耗時很長,后一個任務就不得不一直等待。
所以設計者將任務分成兩種,一種 同步任務 ,另一種是 異步任務 。
同步任務是,在主線程上排隊執行的任務,只有前一個執行完,才能執行后一個;
異步任務是,不進入主線程,而是進入“任務隊列”的任務,只有“任務隊列”通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。
“任務隊列”除了放置任務事件,還可以放置定時事件。即指定某些代碼在多少時間之后執行。知道了這些我們基本上就可以解釋上面兩段代碼為什么會輸出這樣的結果了。
第一段代碼,因為setTimeout()將回調函數推遲了3000毫秒之后執行。如果將setTimeout()第二個參數設置為0,就表示當前代碼執行完以后,立刻執行(0毫秒間隔)指定的回調函數。所以只有在打印出1和3之后,系統才會執行“任務隊列”中的回調函數。
總之,setTimeout(fn,0)的含義是,指定某個任務在主線程最早可得的空閑時間執行,也就是說,盡可能早得執行。它在"任務隊列"的尾部添加一個事件,因此要等到同步任務和"任務隊列"現有的事件都處理完,才會得到執行。強調一遍:它在"任務隊列"的尾部添加一個事件,記住是尾部,添加到"任務隊列"尾部,所以后最后執行。
HTML5標準規定了setTimeout()的第二個參數的最小值(最短間隔),不得低于4毫秒,如果低于這個值,就會自動增加。在此之前,老版本的瀏覽器都將最短間隔設為10毫秒。
setTimeout()只是將事件插入了"任務隊列",必須等到當前代碼(執行棧)執行完,主線程才會去執行它指定的回調函數。要是當前代碼耗時很長,有可能要等很久,所以并沒有辦法保證,回調函數一定會在setTimeout()指定的時間執行。所以他們有時候不一定會守時的。守時的都是好孩子!
阮一峰老師對任務隊列有詳細的介紹,詳情戳這里
五、setTimeout 相熟了解了上面的內容,我們得拉出來溜溜了,直接上測試題:
console.log(1); setTimeout(fn1, 1000); setTimeout(function(){ console.log(2); },0); setTimeout(console.log(3),2000); function fn1(){ console.log(4); } console.log(5); //輸出結果: //1 3 5 2 4(4會延遲一秒)
1.先執行主線程,打印出1;2.遇到第一個setTimeout,1秒后執行回調函數,所以添加到任務隊列;
3.遇到第二個setTimeout,0秒后執行回調函數,再次添加到任務隊列;
4.遇到第三個setTimeout,這個第一個參數不是回調函數,而是一個直接可執行的語句,記得我前面講過的這個是個雜牌軍,它不會添加到任務隊列也不會延遲執行而是直接執行,所以打印出3;
5.繼續執行打印出5;
6.第二個setTimeout,由于是0秒延遲所以主線程任務結束立刻執行,所以打印出2;
7.最后執行第一個setTimeout,一秒后打印出4.
上面的試題明白之后我們就可以明白下面的代碼了:
var timeoutId = setTimeout(function (){ console("hello World"); },1000); clearTimeout(timeoutId); //輸出結果: //不會打印出hello World
1先執行主線程,遇到setTimeout并且第一個參數是回調函數,添加到任務隊列,1秒后執行;2.執行clearTimeout,則還未等到代碼執行就 取消了定時器,所以不會打印出任何內容。
下面我們學習下promise
promise 一、promise 初現ES6 將promise寫進了語言標準,統一了用法,原生提供了Promise對象。
詳細介紹戳這里阮一峰老師進行了詳細的說明;
這里我簡單的說下,我后面會使用到的內容:
Promise 新建后就會立即執行,然后,then方法接受兩個回調函數作為參數,將在當前腳本所有同步任務執行完才會執行。記住這里then之后的回調函數才異步執行的,所以會添加到任務隊列中。
第一個回調函數是Promise對象的狀態變為resolved時調用,第二個回調函數是Promise對象的狀態變為rejected時調用。其中,第二個函數是可選的,不一定要提供。
下面我將以代碼片段的方式,逐漸看出現的各種面試題,加深大家的理解
console.log(1); new Promise((resolve,reject)=>{ console.log(2); resolve() }).then( ()=>{ console.log(3) },()=>{ console.log(4); }); console.log(5); //輸出結果: //1 2 5 3
1.先執行主線程,打印出1;
Promise 新建后就會立即執行,所以打印出2,執行resolve表明執行成功回調;
then的成功執行的是回調函數,所以是異步執行,添加到任務隊列之中,暫不執行;
繼續執行主線程,打印出5;
主線程結束之后執行任務隊列中的回調函數打印出3
console.log(1); new Promise((resolve,reject)=>{ console.log(2); reject() }).then( ()=>{ console.log(3) },()=>{ console.log(4); }); console.log(5); //輸出結果: //1 2 5 4
這個例子同上,只是執行的是異步的失敗的回調函數,所以最后一個打印出的是4
console.log(1); new Promise((resolve,reject)=>{ console.log(2); }).then( ()=>{ console.log(3) }); console.log(4); //輸出結果: //1 2 4
這個例子中打印出4之后沒有打印3,是因為promise中沒有指定是執行成功回調還是失敗的回調所以不會執行then的回調函數
console.log(1); new Promise((resolve,reject)=>{ console.log(2); }).then(console.log(3)); console.log(4); //輸出結果: //1 2 3 4
看到這個有同學可能就懵了,怎么回事怎么是1234而不是1243呢,這需要考察同學們是否細心呢,看這里then中的直接是可執行的語句而不是回調函數,所以會出現這種情況,異步任務必須是回調函數 如果不是回調函數就是同步的了
1.先執行主線程,打印出1;
Promise 新建后就會立即執行,所以打印出2;
then中不是回調函數而是直接可執行的語句,所以直接執行打印出3;
繼續執行主線程,打印出4;
嘻嘻,看了上面的這些例子相信大家已經對promise理解了不少,所以我們繼續深入看看下面這個例子,輸出的結果是什么呢?
console.log(1); new Promise((resolve,reject)=>{ console.log(2); resolve(); console.log(3); }).then( ()=>{ console.log(4) }); console.log(5); //輸出結果: //1 2 3 5 4
大家有沒有寫對呢?
這里大家的疑問估計就是resolve()之后的console.log(3);這個地方咯
這是因為上面代碼中,調用resolve()以后,后面的console.log(3)還是會執行,并且會首先打印出來。因為立即 resolved 的 Promise 是在本輪事件循環的末尾執行,總是晚于本輪循環的同步任務。
所以如果想讓,調用resolve或reject以后,Promise 的使命完成,后繼操作應該放到then方法里面,而不應該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語句,這樣就不會有意外。如下:
console.log(1); new Promise((resolve,reject)=>{ console.log(2); return resolve(); console.log(3); }).then( ()=>{ console.log(4) }); console.log(5); //輸出結果: //1 2 5 4
這樣console.log(3);是不會執行的。
三、promise&setTimeout下面我們在來看如果promise&setTimeout同時出現會發生什么樣的情況呢?如下:
console.log("a"); setTimeout(function() {console.log("b")}, 0); new Promise((resolve, reject) => { for(let i=0; i<10000000; i++) { if(i==999999) { console.log("c"); resolve(); } } console.log("d"); }).then(() => { console.log("e"); }); console.log("f"); //輸出結果: // a c d f e b
大家是不是有些暈,哈哈哈,別著急這里我們得在拓展一點新概念,方便我們理解:事件循環、宏任務和微任務
JavaScript的一大特點就是單線程,而這個線程中擁有唯一的一個事件循環。
一個線程中,事件循環是唯一的,但是任務隊列可以擁有多個。
任務隊列又分為macro-task(宏任務)與micro-task(微任務),它們又被稱為task與jobs。
宏任務(macro-task)大概包括:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering。
微任務(micro-task)大概包括: process.nextTick, Promise, MutationObserver(html5新特性)
事件循環的順序,決定了JavaScript代碼的執行順序。
它從script(整體代碼)開始第一次循環。之后全局上下文進入函數調用棧。
直到調用棧清空(只剩全局),然后執行所有的微任務(micro-task)。
當所有可執行的微任務(micro-task)執行完畢之后。
循環再次從宏任務(macro-task)開始,找到其中一個任務隊列執行完畢,然后再執行所有的微任務(micro-task),這樣一直循環下去。
注:本篇使用的宏任務(macro-task):script(整體代碼), setTimeout, setInterval;微任務(micro-task): Promise。至于其他的瀏覽器沒有,引用了node.js的API,如: setImmediate、 process.nextTick等,至于他們的執行順序可參考這篇文章
比如上述例子,不同類型的任務會分別進入到他們所屬類型的任務隊列,比如所有setTimeout()的回調都會進入到setTimeout任務隊列,既宏任務(macro-task);所有then()回調都會進入到then隊列,既微任務(micro-task)。
當前的整體代碼我們可以認為是宏任務。事件循環從當前整體代碼開始第一次事件循環,然后再執行隊列中所有的微任務,當微任務執行完畢之后,事件循環再找到其中一個宏任務隊列并執行其中的所有任務,然后再找到一個微任務隊列并執行里面的所有任務,就這樣一直循環下去。這就是我所理解的事件循環。
分析上面例子:
1.首先執行整體代碼,第一個打印出來a2.執行到第一個setTimeout時,發現它是宏任務,此時會新建一個setTimeout類型的宏任務隊列并派發當前這個setTimeout的回調函數到剛建好的這個宏任務隊列中去
3.再執行到new Promise,Promise構造函數中的第一個參數在new的時候會直接執行,因此不會進入任何隊列,所以第三個輸出是c
4.執行完resolve()之后,繼續向后執行,打印出d
5.上面有說到Promise.then是微任務,那么這里會生成一個Promise.then類型的微任務隊列,這里的then回調會被push進這個隊列中
6.再向后走打印出f
7.第一輪事件循環的宏任務執行完成(整體代碼看做宏任務)。此時微任務隊列中只有一個Promise.then類型微任務隊列。宏任務隊列中也只有一個setTimeout類型的宏任務隊列。
8.下面執行第一輪事件循環的微任務,很明顯,會打印出e,至此第一輪事件循環完成
9.開始第二輪事件循環:執行setTimeout類型隊列(宏任務隊列)中的所有任務,只有一個任務,所以打印出b
10.第二輪事件的宏任務結束,這個事件循環結束。
再來一個你中有我我中有你的超級例子,體驗下到處是坑的試題,嘿嘿;-)
console.log("a"); setTimeout(function () { console.log("b") new Promise(resolve=> { console.log("c") resolve() }).then(()=> { console.log("d") }) },2000); new Promise((resolve,reject)=>{ console.log("e"); resolve(); console.log("f"); }).then(()=>{ console.log("g") }); console.log("h"); new Promise((resolve,reject)=>{ setTimeout(function () { console.log("i"); },0); }).then(console.log("j")); setTimeout(function () { console.log("k") new Promise(resolve=>{ console.log("l") return resolve() console.log("m") }).then(()=>{ console.log("n") }) },1000); console.log("p"); //輸出結果: //a e f h j p g i //延遲1s 輸出:k l n //再延遲1s 輸出:b c d
1.首先執行整體代碼,第一個打印出來"a";2.執行到第一個setTimeout時,發現它是宏任務,此時會新建一個setTimeout類型的宏任務隊列并派發當前這個setTimeout的回調函數到剛建好的這個宏任務隊列中去,并且輪到它執行時要延遲2秒后再執行;
3.執行到第一個new Promise,Promise構造函數中的第一個參數在new的時候會直接執行,因此不會進入任何隊列,所以第二個輸出是"e",resolve()之后的語句會繼續執行,所以第三個輸出的是"f",Promise.then是微任務,那么這里會生成一個Promise.then類型的微任務隊列,這里的then回調會被push進這個隊列中;
4.再執行整體代碼,第四個打印出來"h";
5.執行到第一個new Promise,Promise構造函數中的第一個參數在new的時候會直接執行,但是這個是一個setTimeout,發現它是宏任務,派發它的回調到上面setTimeout類型的宏任務隊列中去。后面Promise.then中是一個可執行的代碼,并不是回調函數,所以會直接的執行,并不會添加到微任務中去,所以第五個輸出的是:"j";
6.執行到第二個setTimeout時,發現它是宏任務,派發它的回調到上面setTimeout類型的宏任務隊列中去,但是會延遲1s執行;
7.執行整體代碼,第六個輸出的是"p";
8.第一輪事件循環的宏任務執行完成(整體代碼看做宏任務)。此時微任務隊列中只有一個Promise.then類型微任務隊列,它里面有一個任務;宏任務隊列中也只有一個setTimeout類型的宏任務隊列;
9.下面執行第一輪事件循環的微任務,很明顯,第七個輸出的是:"g"。此時第一輪事件循環完成;
10.開始第二輪事件循環:執行setTimeout類型隊列(宏任務隊列)中的所有任務。發現有的有延時有的沒有延時,所以先執行延時最短的宏任務;
11.執行setTimeout,第八個輸出的是"i";
12.緊接著執行延遲1s的setTimeout,所以延遲一秒之后第九個輸出的是:"k";
13.之后遇到new Promise,Promise構造函數中的第一個參數在new的時候會直接執行,因此不會進入任何隊列,所以第十個輸出是"l",之后是一個return語句,所以后面的代碼不會執行,"m"不會被輸出出來;
14.但這里發現了then,又把它push到上面已經被執行完的then隊列中去,這里要注意,因為出現了微任務then隊列,所以這里會執行該隊列中的所有任務(此時只有一個任務),所以第十一個輸出的是"n";
15.再延遲1s執行setTimeout,所以延遲二秒之后第十二個輸出的是:"b";
16.之后遇到new Promise,Promise構造函數中的第一個參數在new的時候會直接執行,因此不會進入任何隊列,所以第十三個輸出是"c";
17.但這里又發現了then,又把它push到上面已經被執行完的then隊列中去,這里要注意,因為出現了微任務then隊列,所以這里會執行該隊列中的所有任務(此時只有一個任務),所以第十四個輸出的是"d";
噗,終于完了,不知道大家有沒有理解呢?
生活就是這樣,你以為度過了一個難關前面就是陽光大道,但現實就是這樣,他會給你再來一個難題,接著看下面的代碼,嘿嘿嘿~~~
async function async1() { console.log("a"); await async2(); console.log("b"); } async function async2() { console.log( "c"); } console.log("d"); setTimeout(function () { console.log("e"); },0); async1(); new Promise(function (resolve) { console.log("x"); resolve(); }).then(function () { console.log("y"); }); console.log("z"); //輸出結果: // d a c x z y b e
是不是有點傻了,怎么又出現了async了,別慌別慌且聽我慢慢道來,在說之前還得大家了解async,阮一峰老師對此有詳細的介紹,詳情戳這里
Async 一、asyncasync的用法,它作為一個關鍵字放到函數前面,用于表示函數是一個異步函數,因為async就是異步的意思, 異步函數也就意味著該函數的執行不會阻塞后面代碼的執行。
我們先來觀察下async的返回值,請看下面的代碼:
async function testAsync() { return "hello async"; } const result = testAsync(); console.log(result); //輸出結果: // Promise { "hello async" }
看到這里我們知道了,saync輸出的是一個promise對象
async 函數(包含函數語句、函數表達式)會返回一個 Promise 對象,如果在函數中 return 一個直接量,async 會把這個直接量通過 Promise.resolve() 封裝成 Promise 對象。
那我們試下沒有返回值會是怎么樣呢?
async function testAsync() { console.log("hello async"); } const result = testAsync(); console.log(result); //輸出結果: // hello async // Promise { undefined }
會返回一個為空的promis對象
二、await從字面意思上看await就是等待,await 等待的是一個表達式,這個表達式的返回值可以是一個promise對象也可以是其他值。
注意到 await 不僅僅用于等 Promise 對象,它可以等任意表達式的結果,所以,await 后面實際是可以接普通函數調用或者直接量的。
function getSomething() { return "something"; } async function testAsync() { return Promise.resolve("hello async"); } async function test() { const v1 = await getSomething(); const v2 = await testAsync(); console.log(v1, v2); } test(); //輸出結果: // something hello async
await 是個運算符,用于組成表達式,await 表達式的運算結果取決于它等的東西,如果它等到的不是一個 Promise 對象,那 await 表達式的運算結果就是它等到的東西。
內容 | 描述 |
---|---|
語法 | [return_value] = await expression; |
表達式(expression) | 一個 Promise 對象或者任何要等待的值。 |
返回值(return_value) | 返回 Promise 對象的處理結果。如果等待的不是 Promise 對象,則返回該值本身 |
但是當遇到await會怎么執行呢?
async函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而await命令就是內部then命令的語法糖。
當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,再接著執行函數體內后面的語句.
即,
當遇到async函數體內的 await test();時候,執行test(),然后得到返回值value(可以是promise也可以是其他值),組成await value;,若 value是promise對象時候,此時返回的Promise會被放入到任務隊列中等待,await會讓出線程,跳出 async函數,繼續執行后續代碼;若 value是其他值,只是不會被添加到任務隊列而已,await也會讓出線程,跳出 async函數,繼續執行后續代碼。
明白了這些,我們分析上面最難的那部分代碼:
1.首先執行整體代碼,遇到兩個saync函數,沒有調用所以繼續向下執行,所以第一個輸出的是:"d";2.執行到第一個setTimeout時,發現它是宏任務,此時會新建一個setTimeout類型的宏任務隊列并派發當前這個setTimeout的回調函數到剛建好的這個宏任務隊列中去,并且輪到它執行時要立刻執行;
3.遇到async1(), async1函數調用,執行async1函數,第二個輸出的是:"a";
4.然后執行到 await async2(),發現 async2 也是個 async 定義的函數,所以直接執行了“console.log("c")”。所以第三個輸出的是:"c";
5.同時async2返回了一個Promise,請注意:此時返回的Promise會被放入到任務隊列中等待,await會讓出線程,接下來就會跳出 async1函數,繼續往下執行!??!
6.執行到 new Promise,前面說過了promise是立即執行的,所以第四個輸出的是:"x";
7.然后執行到 resolve 的時候,resolve這個任務就被放到任務隊列中等待,然后跳出Promise繼續往下執行,所以第五個輸出的是:"z";
8.現在調用??粘鰜砹?,事件循環就會去任務隊列里面取任務繼續放到調用棧里面;
9.取到的第一個任務,就是前面 async1 放進去的Promise,執行Promise時候,遇到resolve或者reject函數,這次會又被放到任務隊列中等待,然后再次跳出 async1函數 繼續下一個任務?。?!
10.接下來取到的下一個任務,就是前面 new Promise 放進去的 resolve回調,執行then,所以第六個輸出的是:"y";
11.調用棧再次空出來了,事件循環就取到了下一個任務,async1 函數中的 async2返回的promise對象的resolve或者reject函數執行,因為 async2 并沒有return任何東西,所以這個resolve的參數是undefined;
12.此時 await 定義的這個 Promise 已經執行完并且返回了結果,所以可以繼續往下執行 async1函數 后面的任務了,那就是“console.log("b")”,所以第七個輸出的是:"b";
13.調用棧再次的空了出來終于執行setTimeout的宏任務,所以第八個輸出的是:"e"
哇(@ο@) 哇~,解決了小伙伴們明白沒有,希望大家了解了就再也不怕面試這種題目啦!
本想著簡單的寫下面試題的解決步驟沒想到一下子寫了這么多,耐心讀到這里的小伙伴都是非常棒的,愿你在技術的路上越走越遠!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/102177.html
摘要:最近項目中用的比較多,所以特地去了解,模仿一下實現先來看看使用的方法通過是通過使用生成器配合方法模擬的一個同步操作,這個技術有效的避免了傳統回調和形成的回調地獄。 最近項目中 asyn & await 用的比較多,所以特地去了解,模仿一下實現~ 先來看看 使用 async & await 的方法 async function d () { try { const a = a...
摘要:但是中的這種情況與抽象反應器模式如何描述完全不同。在處理一個階段之后并且在移到下一個隊列之前,事件循環將處理兩個中間隊列,直到中間隊列中沒有剩余的項目。如果沒有任務則循環退出,每一次隊列處理都被視為事件循環的一個階段。 Promise && async/await的理解和用法 為什么需要promise(承諾)這個東西 在之前我們處理異步函數都是用回調這個方法,回調嵌套的時候會發現 閱讀...
摘要:前文該系列下的前幾篇文章分別對不同的幾種異步方案原理進行解析,本文將介紹一些實際場景和一些常見的面試題。流程調度里比較常見的一種錯誤是看似串行的寫法,可以感受一下這個例子判斷以下幾種寫法的輸出結果辨別輸出順序這類題目一般出現在面試題里。 前文 該系列下的前幾篇文章分別對不同的幾種異步方案原理進行解析,本文將介紹一些實際場景和一些常見的面試題。(積累不太夠,后面想到再補) 正文 流程調度...
摘要:當然大多數情況下就是我們是在單線程下進行的操作,所以大多數情況下是建議用而不用的,就是速度的原因。 第三階段 JAVA常見對象的學習 StringBuffer和StringBuilder類 (一) StringBuffer類的概述 (1) 基本概述 下文以StringBuffer為例 前面我們用字符串做拼接,比較耗時并且也耗內存(每次都會構造一個新的string對象),而這種拼接操作又...
描述如下 我們要同時發多個相同的請求,第一個請求成功后,剩余結果都不會發出,返回結果是成果。 假如第一個反饋失敗,第二個是成功,后面就不會發出,后面都直接反饋成功。第三個才是成功的話,后面就不會在發出,后面都反饋成功。依次如此處理,直至最后一個?! 〔l: 一個接口請求還處于pending,短時間內就發送相同的請求 asyncfunctionfetchData(a){ const...
閱讀 1544·2021-11-04 16:10
閱讀 2802·2021-09-30 09:48
閱讀 2847·2019-08-29 11:31
閱讀 1586·2019-08-28 18:22
閱讀 3236·2019-08-26 13:44
閱讀 1327·2019-08-26 13:42
閱讀 2852·2019-08-26 10:20
閱讀 762·2019-08-23 17:00