javascript基礎(chǔ)知識(shí)問(wèn)答-作用域和閉包

1.理解詞法作用域和動(dòng)態(tài)作用域
2.理解JavaScript的作用域和作用域鏈
3.理解JavaScript的執(zhí)行上下文棧,可以應(yīng)用堆棧信息快速定位問(wèn)題
4.this的原理以及幾種不同使用場(chǎng)景的取值
5.閉包的實(shí)現(xiàn)原理和作用,可以列舉幾個(gè)開(kāi)發(fā)中閉包的實(shí)際應(yīng)用
6.理解堆棧溢出和內(nèi)存泄漏的原理,如何防止
7.如何處理循環(huán)的異步操作

1.理解詞法作用域和動(dòng)態(tài)作用域

詞法作用域,也叫靜態(tài)作用域,它的作用域是指在詞法分析階段就確定了,不會(huì)改變。動(dòng)態(tài)作用域是在運(yùn)行時(shí)根據(jù)程序的流程信息來(lái)動(dòng)態(tài)確定的,而不是寫(xiě)代碼時(shí)進(jìn)行靜態(tài)確定的。

需要明確的是,Javascript并不具有動(dòng)態(tài)作用域,它只有詞法作用域,簡(jiǎn)單明了。但是,它的 eval()、with、this機(jī)制某種程度上很像動(dòng)態(tài)作用域,使用上要特別注意。

2.理解JavaScript的作用域和作用域鏈

作用域是在運(yùn)行代碼中的某些特定部分中的變量,函數(shù)和對(duì)象的可訪問(wèn)性。作用于決定了代碼區(qū)塊中變量和其他資源的可見(jiàn)性。作用域最大的用處就是隔離變量,不同作用域下同名變量不會(huì)有沖突。

ES6 之前 JavaScript 沒(méi)有塊級(jí)作用域,只有全局作用域和函數(shù)作用域。ES6 的到來(lái),為我們提供了‘塊級(jí)作用域’,可通過(guò)新增命令 let 和 const 來(lái)體現(xiàn)。

當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。由子級(jí)作用域返回父級(jí)作用域中尋找變量,就叫做作用域鏈。作用域鏈?zhǔn)潜WC執(zhí)行環(huán)境有權(quán)訪問(wèn)的所有變量和函數(shù)的有序訪問(wèn)。

延長(zhǎng)作用域鏈:
執(zhí)行環(huán)境的類型只有兩種,全局和局部(函數(shù))。但是有些語(yǔ)句可以在作用域鏈的前端臨時(shí)增加一個(gè)變量對(duì)象,該變量對(duì)象會(huì)在代碼執(zhí)行后被移除。
具體來(lái)說(shuō)就是執(zhí)行這兩個(gè)語(yǔ)句時(shí),作用域鏈都會(huì)得到加強(qiáng)。
1、try - catch 語(yǔ)句的catch塊;會(huì)創(chuàng)建一個(gè)新的變量對(duì)象,包含的是被拋出的錯(cuò)誤對(duì)象的聲明。
2、with 語(yǔ)句。with 語(yǔ)句會(huì)將指定的對(duì)象添加到作用域鏈中

3.理解JavaScript的執(zhí)行上下文棧,可以應(yīng)用堆棧信息快速定位問(wèn)題

執(zhí)行上下文是評(píng)估和執(zhí)行JavaScript代碼的環(huán)境的抽象概念。每當(dāng)JavaScript代碼在運(yùn)行的時(shí)候,它都是在執(zhí)行上下文中運(yùn)行。

執(zhí)行棧,也就是其他編程語(yǔ)言中所說(shuō)的“調(diào)用?!?,是一種擁有LIFO(后進(jìn)先出)數(shù)據(jù)結(jié)構(gòu)的棧,被用來(lái)存儲(chǔ)代碼運(yùn)行時(shí)創(chuàng)建的所有執(zhí)行上下文。

執(zhí)行上下文總共有三種類型

  1. 全局執(zhí)行上下文
  2. 函數(shù)執(zhí)行上下文
  3. Eval函數(shù)執(zhí)行上下文

執(zhí)行上下文的聲明周期包含三個(gè)階段創(chuàng)建階段執(zhí)行階段回收階段

創(chuàng)建階段
  • 創(chuàng)建變量對(duì)象
  • 創(chuàng)建作用域鏈
  • 確定this 指向

4.this的原理以及幾種不同使用場(chǎng)景的取值

場(chǎng)景一:構(gòu)造函數(shù)

所謂構(gòu)造函數(shù)就是用來(lái)new對(duì)象的函數(shù)。其實(shí)嚴(yán)格來(lái)說(shuō),所有的函數(shù)都可以new一個(gè)對(duì)象,但是有些函數(shù)的定義是為了new一個(gè)對(duì)象,而有些函數(shù)則不是。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫(xiě)(規(guī)則約定)。例如:Object、Array、Function等

function Foo(){
  this.name='Apple',
  this.type='fruit';
  console.log(this);//Foo{name:'Apple',type:'fruit'}
}
var f1=new Foo();
console.log(f1.name,f1.type)//Apple,fruit

以上代碼中,如果函數(shù)作為構(gòu)造函數(shù)用,那么其中的this就代表它即將new出來(lái)的對(duì)象。
注意:以上僅限new Foo()的情況,即Foo函數(shù)作為構(gòu)造函數(shù)的情況。如果直接調(diào)用Foo函數(shù),而不是new Foo(),情況就大不一樣了。

function Foo(){
  this.name='Apple',
  this.type='fruit';
  console.log(this);//Window{top:Window,window:Window……}
}
Foo();

這種情況下this是window。
在構(gòu)造函數(shù)的prototype中,this代表什么。

function Fn(){
  this.name='Apple',
  this.type='fruit';
}
Fn.prototype.getName=function(){
      console.log(this.name)
}
var f1=new Fn();
f1.getName();//Apple

如上代碼,在Fn.prototype.getName函數(shù)中,this指向的是f1對(duì)象。因此可以通過(guò)this.name獲取f1.name的值。

其實(shí),不僅僅是構(gòu)造函數(shù)的prototype,即便是在整個(gè)原型鏈中,this代表的也都是當(dāng)前對(duì)象的值。

場(chǎng)景二:函數(shù)作為對(duì)象的一個(gè)屬性

如果函數(shù)作為對(duì)象的一個(gè)屬性時(shí),并且作為對(duì)象的一個(gè)屬性被調(diào)用時(shí),函數(shù)中的this指向該對(duì)象。

var obj={
    x:10,
    fn:function(){
        console.log(this);//Object{x:10,fn:function}
    }
}
obj.fn();

以上代碼中,fn不僅作為一個(gè)對(duì)象的一個(gè)屬性,而且的確是作為對(duì)象的一個(gè)屬性被調(diào)用。結(jié)果this就是obj對(duì)象。

var obj={
    x:10,
    fn:function(){
        console.log(this); //Window{top:Window,window:Window……}
    }
}
var fn1=obj.fn;
fn1();

以上代碼,如果fn函數(shù)被復(fù)制到了另一個(gè)變量中,并沒(méi)有作為obj的一個(gè)屬性被調(diào)用,那么this的值就是window,this.x就是undefined。

場(chǎng)景三:函數(shù)用call或者apply調(diào)用

當(dāng)一個(gè)函數(shù)被call和apply調(diào)用時(shí),this的值就取傳入的對(duì)象的值。

var obj = {
    x:10 
}
var fn = function(){
    console.log(this); //Object{x:10}
    console.log(this.x); //10
}
fn.call(obj);

場(chǎng)景四:全局&調(diào)用普通函數(shù)

在全局環(huán)境下,this永遠(yuǎn)是window。

console.log(this === window);//true

普通函數(shù)在調(diào)用時(shí),其中的this也都是window。

var x= 10;
var fn = function (){
    console.log(this);//Window{top:Window;window:Window……}
    console.log(this.x);//10
}
fn()

下面情況要注意:

var obj = {
    x:10,
    fn:function(){
        function f(){
            console.log(this)//Window{top:Window;window:Window……}
            console.log(this.x);//undefined
        }
       f();  
  }
}
obj.fn();

函數(shù)f雖然是在obj.fn內(nèi)部定義的,但是它仍然是一個(gè)普通的函數(shù),this仍然指向window。

5.閉包的實(shí)現(xiàn)原理和作用,可以列舉幾個(gè)開(kāi)發(fā)中閉包的實(shí)際應(yīng)用

閉包是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。換句話說(shuō),JavaScript中所有的function都是一個(gè)閉包。

一般來(lái)說(shuō),嵌套的function所產(chǎn)生的閉包更為強(qiáng)大。

function a() { 
 var i = 0; 
 function b() { alert(++i); } //函數(shù)b嵌套在函數(shù)a內(nèi)部;
 return b;//函數(shù)a返回函數(shù)b。
}
var c = a();
c();

這樣在執(zhí)行完var c=a()后,變量c實(shí)際上是指向了函數(shù)b,再執(zhí)行c()后就會(huì)彈出一個(gè)窗口顯示i的值(第一次為1)。這段代碼其實(shí)就創(chuàng)建了一個(gè)閉包,為什么?因?yàn)楹瘮?shù)a外的變量c引用了函數(shù)a內(nèi)的函數(shù)b,就是說(shuō):

當(dāng)函數(shù)a的內(nèi)部函數(shù)b被函數(shù)a外的一個(gè)變量引用的時(shí)候,就創(chuàng)建了一個(gè)閉包.

所謂“閉包”,就是在構(gòu)造函數(shù)體內(nèi)定義另外的函數(shù)作為目標(biāo)對(duì)象的方法函數(shù),而這個(gè)對(duì)象的方法函數(shù)反過(guò)來(lái)引用外層函數(shù)體中的臨時(shí)變量。這使得只要目標(biāo) 對(duì)象在生存期內(nèi)始終能保持其方法,就能間接保持原構(gòu)造函數(shù)體當(dāng)時(shí)用到的臨時(shí)變量值。盡管最開(kāi)始的構(gòu)造函數(shù)調(diào)用已經(jīng)結(jié)束,臨時(shí)變量的名稱也都消失了,但在目 標(biāo)對(duì)象的方法內(nèi)卻始終能引用到該變量的值,而且該值只能通這種方法來(lái)訪問(wèn)。即使再次調(diào)用相同的構(gòu)造函數(shù),但只會(huì)生成新對(duì)象和方法,新的臨時(shí)變量只是對(duì)應(yīng)新 的值,和上次那次調(diào)用的是各自獨(dú)立的。

簡(jiǎn)而言之,閉包的作用就是在a執(zhí)行完并返回后,閉包使得Javascript的垃圾回收機(jī)制GC不會(huì)收回a所占用的資源,因?yàn)閍的內(nèi)部函數(shù)b的執(zhí)行需要依賴a中的變量。這是對(duì)閉包作用的非常直白的描述,不專業(yè)也不嚴(yán)謹(jǐn),但大概意思就是這樣,理解閉包需要循序漸進(jìn)的過(guò)程。

當(dāng)定義函數(shù)a的時(shí)候,js解釋器會(huì)將函數(shù)a的作用域鏈(scope chain)設(shè)置為定義a時(shí)a所在的“環(huán)境”,如果a是一個(gè)全局函數(shù),則scope chain中只有window對(duì)象。
當(dāng)執(zhí)行函數(shù)a的時(shí)候,a會(huì)進(jìn)入相應(yīng)的執(zhí)行環(huán)境(excution context)。
在創(chuàng)建執(zhí)行環(huán)境的過(guò)程中,首先會(huì)為a添加一個(gè)scope屬性,即a的作用域,其值就為第1步中的scope chain。即a.scope=a的作用域鏈。
然后執(zhí)行環(huán)境會(huì)創(chuàng)建一個(gè)活動(dòng)對(duì)象(call object)。活動(dòng)對(duì)象也是一個(gè)擁有屬性的對(duì)象,但它不具有原型而且不能通過(guò)JavaScript代碼直接訪問(wèn)。創(chuàng)建完活動(dòng)對(duì)象后,把活動(dòng)對(duì)象添加到a的作用域鏈的最頂端。此時(shí)a的作用域鏈包含了兩個(gè)對(duì)象:a的活動(dòng)對(duì)象和window對(duì)象。
下一步是在活動(dòng)對(duì)象上添加一個(gè)arguments屬性,它保存著調(diào)用函數(shù)a時(shí)所傳遞的參數(shù)。

最后把所有函數(shù)a的形參和內(nèi)部的函數(shù)b的引用也添加到a的活動(dòng)對(duì)象上。在這一步中,完成了函數(shù)b的的定義,因此如同第3步,函數(shù)b的作用域鏈被設(shè)置為b所被定義的環(huán)境,即a的作用域。

到此,整個(gè)函數(shù)a從定義到執(zhí)行的步驟就完成了。此時(shí)a返回函數(shù)b的引用給c,又函數(shù)b的作用域鏈包含了對(duì)函數(shù)a的活動(dòng)對(duì)象的引用,也就是說(shuō)b可以訪問(wèn)到a中定義的所有變量和函數(shù)。函數(shù)b被c引用,函數(shù)b又依賴函數(shù)a,因此函數(shù)a在返回后不會(huì)被GC回收。

當(dāng)函數(shù)b執(zhí)行的時(shí)候亦會(huì)像以上步驟一樣。因此,執(zhí)行時(shí)b的作用域鏈包含了3個(gè)對(duì)象:b的活動(dòng)對(duì)象、a的活動(dòng)對(duì)象和window對(duì)象,如下圖所示:


函數(shù)b的作用鏈

如圖所示,當(dāng)在函數(shù)b中訪問(wèn)一個(gè)變量的時(shí)候,搜索順序是:

先搜索自身的活動(dòng)對(duì)象,如果存在則返回,如果不存在將繼續(xù)搜索函數(shù)a的活動(dòng)對(duì)象,依次查找,直到找到為止。

如果函數(shù)b存在prototype原型對(duì)象,則在查找完自身的活動(dòng)對(duì)象后先查找自身的原型對(duì)象,再繼續(xù)查找。這就是Javascript中的變量查找機(jī)制。

如果整個(gè)作用域鏈上都無(wú)法找到,則返回undefined。

小結(jié),本段中提到了兩個(gè)重要的詞語(yǔ):函數(shù)的定義與執(zhí)行。文中提到函數(shù)的作用域是在定義函數(shù)時(shí)候就已經(jīng)確定,而不是在執(zhí)行的時(shí)候確定。用一段代碼來(lái)說(shuō)明這個(gè)問(wèn)題

function f(x) { 
  var g = function () { return x; }
  return g;
}
var h = f(1);
alert(h());

這段代碼中變量h指向了f中的那個(gè)匿名函數(shù)(由g返回)。

假設(shè)函數(shù)h的作用域是在執(zhí)行alert(h())確定的,那么此時(shí)h的作用域鏈?zhǔn)牵篽的活動(dòng)對(duì)象->alert的活動(dòng)對(duì)象->window對(duì)象。

假設(shè)函數(shù)h的作用域是在定義時(shí)確定的,就是說(shuō)h指向的那個(gè)匿名函數(shù)在定義的時(shí)候就已經(jīng)確定了作用域。那么在執(zhí)行的時(shí)候,h的作用域鏈為:h的活動(dòng)對(duì)象->f的活動(dòng)對(duì)象->window對(duì)象。

如果第一種假設(shè)成立,那輸出值就是undefined;如果第二種假設(shè)成立,輸出值則為1。
運(yùn)行結(jié)果證明了第2個(gè)假設(shè)是正確的,說(shuō)明函數(shù)的作用域確實(shí)是在定義這個(gè)函數(shù)的時(shí)候就已經(jīng)確定了。

閉包的應(yīng)用場(chǎng)景

  1. 保護(hù)函數(shù)內(nèi)的變量安全。以最開(kāi)始的例子為例,函數(shù)a中i只有函數(shù)b才能訪問(wèn),而無(wú)法通過(guò)其他途徑訪問(wèn)到,因此保護(hù)了i的安全性。

  2. 在內(nèi)存中維持一個(gè)變量。依然如前例,由于閉包,函數(shù)a中i的一直存在于內(nèi)存中,因此每次執(zhí)行c(),都會(huì)給i自加1。

  3. 通過(guò)保護(hù)變量的安全實(shí)現(xiàn)JS私有屬性和私有方法(不能被外部訪問(wèn))
    私有屬性和方法在Constructor外是無(wú)法被訪問(wèn)的

function Constructor(...) {
var that = this;
var membername = value;
function membername(...) {...}
}

以上3點(diǎn)是閉包最基本的應(yīng)用場(chǎng)景,很多經(jīng)典案例都源于此。
在Javascript中,如果一個(gè)對(duì)象不再被引用,那么這個(gè)對(duì)象就會(huì)被GC回收。如果兩個(gè)對(duì)象互相引用,而不再被第3者所引用,那么這兩個(gè)互相引用的對(duì)象也會(huì)被回收。因?yàn)楹瘮?shù)a被b引用,b又被a外的c引用,這就是為什么函數(shù)a執(zhí)行后不會(huì)被回收的原因。
var聲明的變量由于不存在塊級(jí)作用域所以可以在全局環(huán)境中調(diào)用,而let聲明的變量由于存在塊級(jí)作用域所以不能在全局環(huán)境中調(diào)用。

       var a=[];
          for(var i=0;i<10;i++){
              a[i]=function(){
                  console.log(i);
              };
            }
        a[6](); //10  
       var b=[];
            for(let i=0;i<10;i++){
                b[i]=function(){
                    console.log(i);
                };
          }
    b[6]();//6

6.理解堆棧溢出和內(nèi)存泄漏的原理,如何防止

內(nèi)存泄露:指一塊被分配的內(nèi)存既不能使用,又不能回收,直到瀏覽器進(jìn)程結(jié)束

JS的回收機(jī)制

JavaScript垃圾回收的機(jī)制很簡(jiǎn)單:找出不再使用的變量,然后釋放掉其占用的內(nèi)存,但是這個(gè)過(guò)程不是實(shí)時(shí)的,因?yàn)槠溟_(kāi)銷比較大,所以垃圾回收系統(tǒng)(GC)會(huì)按照固定的時(shí)間間隔,周期性的執(zhí)行。

到底哪個(gè)變量是沒(méi)有用的?所以垃圾收集器必須跟蹤到底哪個(gè)變量沒(méi)用,對(duì)于不再有用的變量打上標(biāo)記,以備將來(lái)收回其內(nèi)存。用于標(biāo)記的無(wú)用變量的策略可能因?qū)崿F(xiàn)而有所區(qū)別,通常情況下有兩種實(shí)現(xiàn)方式:標(biāo)記清除引用計(jì)數(shù)。引用計(jì)數(shù)不太常用,標(biāo)記清除較為常用

標(biāo)記清除

js中最常用的垃圾回收方式就是標(biāo)記清除。當(dāng)變量進(jìn)入環(huán)境時(shí),例如,在函數(shù)中聲明一個(gè)變量,就將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”。從邏輯上講,永遠(yuǎn)不能釋放進(jìn)入環(huán)境的變量所占用的內(nèi)存,因?yàn)橹灰獔?zhí)行流進(jìn)入相應(yīng)的環(huán)境,就可能會(huì)用到它們。而當(dāng)變量離開(kāi)環(huán)境時(shí),則將其標(biāo)記為“離開(kāi)環(huán)境”。

function test(){
  var a=10;//被標(biāo)記,進(jìn)入環(huán)境
  var b=20;//被標(biāo)記,進(jìn)入環(huán)境
}
test();//執(zhí)行完畢之后a、b又被標(biāo)記離開(kāi)環(huán)境,被回收

引用計(jì)數(shù)

引用計(jì)數(shù)的含義是跟蹤記錄每個(gè)值被引用的次數(shù)。當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型值(function object array)賦給該變量時(shí),則這個(gè)值的引用次數(shù)就是1。如果同一個(gè)值又被賦給另一個(gè)變量,則該值的引用次數(shù)加1。相反,如果包含對(duì)這個(gè)值引用的變量又取得了另外一個(gè)值,則這個(gè)值的引用次數(shù)減1。當(dāng)這個(gè)值的引用次數(shù)變成0時(shí),則說(shuō)明沒(méi)有辦法再訪問(wèn)這個(gè)值了,因而就可以將其占用的內(nèi)存空間回收回來(lái)。這樣,當(dāng)垃圾回收器下次再運(yùn)行時(shí),它就會(huì)釋放那些引用次數(shù)為0的值所占用的內(nèi)存。

function test(){
  var a={};//a的引用次數(shù)為0
  var b=a;//a的引用次數(shù)加1,為1
  var c=a;//a的引用次數(shù)加1,為2
  var b={};//a的引用次數(shù)減1,為1
}

哪些情況會(huì)造成內(nèi)存泄露

1.意外的全局變量引起的內(nèi)存泄露

function leak(){
  leak="xxx";//leak成為一個(gè)全局變量,不會(huì)被回收
}

2.閉包引起的泄露

function bindEvent(){
  var obj=document.createElement("XXX");
  obj.οnclick=function(){
    //Even if it's a empty function
  }
}

閉包可以維持函數(shù)內(nèi)局部變量,使其得不到釋放。 上例定義事件回調(diào)時(shí),由于是函數(shù)內(nèi)定義函數(shù),并且內(nèi)部函數(shù)--事件回調(diào)的引用外暴了,形成了閉包。
解決之道,將事件處理函數(shù)定義在外部,解除閉包,或者在定義事件處理函數(shù)的外部函數(shù)中,刪除對(duì)dom的引用。

//將事件處理函數(shù)定義在外部
function onclickHandler(){
  //do something
}
function bindEvent(){
  var obj=document.createElement("XXX");
  obj.οnclick=onclickHandler;
}
//在定義事件處理函數(shù)的外部函數(shù)中,刪除對(duì)dom的引用
function bindEvent(){
  var obj=document.createElement("XXX");
  obj.οnclick=function(){
    //Even if it's a empty function
  }
  obj=null;
}

3.沒(méi)有清理的DOM元素引用

var elements={
    button: document.getElementById("button"),
    image: document.getElementById("image"),
    text: document.getElementById("text")
};
function doStuff(){
    image.src="http://some.url/image";
    button.click():
    console.log(text.innerHTML)
}
function removeButton(){
    document.body.removeChild(document.getElementById('button'))
}
  1. 被遺忘的定時(shí)器或者回調(diào)

var someResouce=getData();
setInterval(function(){
    var node=document.getElementById('Node');
    if(node){
        node.innerHTML=JSON.stringify(someResouce)
    }
},1000)

這樣的代碼很常見(jiàn), 如果 id 為 Node 的元素從 DOM 中移除, 該定時(shí)器仍會(huì)存在, 同時(shí), 因?yàn)榛卣{(diào)函數(shù)中包含對(duì) someResource 的引用, 定時(shí)器外面的 someResource 也不會(huì)被釋放。

5.子元素存在引起的內(nèi)存泄露


圖片.png

黃色是指直接被 js變量所引用,在內(nèi)存里,紅色是指間接被 js變量所引用,如上圖,refB 被 refA 間接引用,導(dǎo)致即使 refB 變量被清空,也是不會(huì)被回收的子元素 refB 由于 parentNode 的間接引用,只要它不被刪除,它所有的父元素(圖中紅色部分)都不會(huì)被刪除。

怎樣避免內(nèi)存泄露

1)減少不必要的全局變量,或者生命周期較長(zhǎng)的對(duì)象,及時(shí)對(duì)無(wú)用的數(shù)據(jù)進(jìn)行垃圾回收;

2)注意程序邏輯,避免“死循環(huán)”之類的 ;

3)避免創(chuàng)建過(guò)多的對(duì)象 原則:不用了的東西要及時(shí)歸還。

7.如何處理循環(huán)的異步操作

1.不需要等待結(jié)果的異步循環(huán)

async function processArray(array) {
  array.forEach(async (item) => {
    await func(item);
  })
  console.log('Done!');
}
function delay() {
  return new Promise(resolve => setTimeout(resolve, 300));
}

async function delayedLog(item) {
  // notice that we can await a function
  // that returns a promise
  await delay();
  console.log(item);
}
async function processArray(array) {
  array.forEach(async (item) => {
    await delayedLog(item);
  })
  console.log('Done!');
}

processArray([1, 2, 3]);

結(jié)果輸出為

Done!
1
2
3

如果不需要等結(jié)果這樣寫(xiě)是ok的,但是在大多數(shù)案例里這不是個(gè)很好的邏輯。

2.線性處理數(shù)組

要等待結(jié)果,我們應(yīng)該返回到老式的 for 循環(huán),但這一次為了更好的可讀性我們可以使用現(xiàn)代寫(xiě)法 for..of

sync function processArray(array) {
  for (const item of array) {
    await delayedLog(item);
  }
  console.log('Done!');
}

結(jié)果輸出:

1
2
3
Done!

該代碼將依次處理每一項(xiàng)。但是我們可以使用并行運(yùn)行。

3.并行處理數(shù)組

async function processArray(array) {
// map array to promises
const promises = array.map(delayedLog);
// wait until all promises are resolved
await Promise.all(promises);
console.log('Done!');
}
這段代碼將并行運(yùn)行許多delayLog 任務(wù)。但是對(duì)于非常大的數(shù)組要小心(并行的任務(wù)太多對(duì)CPU或內(nèi)存來(lái)說(shuō)可能比較吃力)。

也不要混淆“并行”與真正的線程和并行。該代碼不能保證真正的并行執(zhí)行。這取決于您的 item函數(shù)(在本演示中是delayedLog)。網(wǎng)絡(luò)請(qǐng)求、webworker 和其他一些任務(wù)可以并行執(zhí)行。

參考鏈接:
http://www.itdecent.cn/p/70b38c7ab69c
http://www.itdecent.cn/p/2c3c8890dff0
http://www.frontopen.com/1702.html
https://www.cnblogs.com/wangfupeng1988/p/3988422.html
https://blog.csdn.net/michael8512/article/details/77888000
http://www.itdecent.cn/p/9dd1014f7f1c

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容