国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

由一道題引申出的事件循環(huán)、letvar用法、iife、塊級(jí)作用域

animabear / 2440人閱讀

摘要:和塊級(jí)作用域?qū)嶋H上為新增了塊級(jí)作用域。這表示外層代碼塊不受內(nèi)層代碼塊的影響。塊級(jí)作用域的出現(xiàn),實(shí)際上使得獲得廣泛應(yīng)用的立即執(zhí)行函數(shù)表達(dá)式不再必要了。其他騷氣方法參考阮老師并發(fā)模型與事件循環(huán)

沒(méi)有錯(cuò),這道題就是:

for (var i = 0; i< 10; i++){
    setTimeout(() => {
        console.log(i);
    }, 1000)
} // 10 10 10 10 ...

為什么這里會(huì)出現(xiàn)10次10,而不是我們預(yù)期的0-9呢?我們要如何修改達(dá)到預(yù)期效果呢?

運(yùn)行時(shí)&&事件循環(huán)

首先我們得理解setTimeout中函數(shù)的執(zhí)行時(shí)機(jī),這里就要講到一個(gè)運(yùn)行時(shí)的概念。

函數(shù)調(diào)用形成了一個(gè)棧幀。

function foo(b) {
  var a = 10;
  return a + b + 11;
}

function bar(x) {
  var y = 3;
  return foo(x * y);
}

console.log(bar(7)); // 返回 42

當(dāng)調(diào)用 bar 時(shí),創(chuàng)建了第一個(gè)幀 ,幀中包含了 bar 的參數(shù)和局部變量。當(dāng) bar 調(diào)用 foo時(shí),第二個(gè)幀就被創(chuàng)建,并被壓到第一個(gè)幀之上,幀中包含了 foo 的參數(shù)和局部變量。當(dāng) foo返回時(shí),最上層的幀就被彈出棧(剩下 bar 函數(shù)的調(diào)用幀 )。當(dāng) bar 返回的時(shí)候,棧就空了。

對(duì)象被分配在一個(gè)堆中,即用以表示一大塊非結(jié)構(gòu)化的內(nèi)存區(qū)域。

隊(duì)列

一個(gè) JavaScript 運(yùn)行時(shí)包含了一個(gè)待處理的消息隊(duì)列。每一個(gè)消息都關(guān)聯(lián)著一個(gè)用以處理這個(gè)消息的函數(shù)。

在事件循環(huán)(Event Loop)期間的某個(gè)時(shí)刻,運(yùn)行時(shí)從最先進(jìn)入隊(duì)列的消息開始處理隊(duì)列中的消息。為此,這個(gè)消息會(huì)被移出隊(duì)列,并作為輸入?yún)?shù)調(diào)用與之關(guān)聯(lián)的函數(shù)。正如前面所提到的,調(diào)用一個(gè)函數(shù)總是會(huì)為其創(chuàng)造一個(gè)新的棧幀。

函數(shù)的處理會(huì)一直進(jìn)行到執(zhí)行棧再次為空為止;然后事件循環(huán)將會(huì)處理隊(duì)列中的下一個(gè)消息(如果還有的話)。

與這題的關(guān)聯(lián)

這里setTimeout會(huì)等到當(dāng)前隊(duì)列執(zhí)行完了之后再執(zhí)行,即for循環(huán)結(jié)束后執(zhí)行,而這個(gè)時(shí)候i的值已經(jīng)是10了,所以會(huì)打印出來(lái)10個(gè)10這樣的結(jié)果。

要是想得到預(yù)期效果,簡(jiǎn)單的刪除setTimeout也是可行的。當(dāng)然也可以這樣改setTimeout(console.log, 1000, i);i作為參數(shù)傳入函數(shù)。

引申出其他

仔細(xì)查閱規(guī)范可知,異步任務(wù)可分為 taskmicrotask 兩類,不同的API注冊(cè)的異步任務(wù)會(huì)依次進(jìn)入自身對(duì)應(yīng)的隊(duì)列中,然后等待 Event Loop 將它們依次壓入執(zhí)行棧中執(zhí)行。

(macro)task主要包含:script(整體代碼)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 環(huán)境)

microtask主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 環(huán)境)

附上一幅圖更清楚的了解一下

每一次Event Loop觸發(fā)時(shí):

執(zhí)行完主執(zhí)行線程中的任務(wù)。

取出micro-task中任務(wù)執(zhí)行直到清空。

取出macro-task中一個(gè)任務(wù)執(zhí)行。

取出micro-task中任務(wù)執(zhí)行直到清空。

重復(fù)3和4。

其實(shí)promise的then和catch才是microtask,本身的內(nèi)部代碼不是。

ps: 再額外附上一道題
new Promise(resolve => {
    resolve(1);
    Promise.resolve().then(() => console.log(2));
    console.log(4)
}).then(t => console.log(t));
console.log(3);

這道題比較基礎(chǔ),答案為4321。先執(zhí)行同步任務(wù),打印出43,然后分析微任務(wù),2先入任務(wù)隊(duì)列先執(zhí)行,再打印出1。

這里還有幾種變種,結(jié)果類似。

let promise1 = new Promise(resolve => {
  resolve(2);
});
new Promise(resolve => {
    resolve(1);
    Promise.resolve(2).then(v => console.log(v));
      //Promise.resolve(Promise.resolve(2)).then(v => console.log(v));
      //Promise.resolve(promise1).then(v => console.log(v));
      //new Promise(resolve=>{resolve(2)}).then(v => console.log(v));
    console.log(4)
}).then(t => console.log(t));
console.log(3);

不過(guò)要值得注意的是一下兩種情況:

let thenable = {
  then: function(resolve, reject) {
    resolve(2);
  }
};
new Promise(resolve => {
  resolve(1);
  new Promise(resolve => {
    resolve(promise1);
  }).then(v => {
    console.log(v);
  });
  // Promise.resolve(thenable).then(v => {
  //   console.log(v);
  // });
  console.log(4);
}).then(t => console.log(t));
console.log(3);
let promise1 = new Promise(resolve => {
  resolve(thenable);
});
new Promise(resolve => {
  resolve(1);
  Promise.resolve(promise1).then(v => {
    console.log(v);
  });
  // new Promise(resolve => {
  //   resolve(promise1);
  // }).then(v => {
  //   console.log(v);
  // });
  console.log(4);
}).then(t => console.log(t));
console.log(3);

結(jié)果為4312。有人可能會(huì)說(shuō)阮老師這篇文章里提過(guò)

Promise.resolve("foo")
// 等價(jià)于
new Promise(resolve => resolve("foo"))

那為什么這兩個(gè)的結(jié)果不一樣呢?

請(qǐng)注意這里resolve的前提條件是參數(shù)是一個(gè)原始值,或者是一個(gè)不具有then方法的對(duì)象,而其他情況是怎樣的呢,stackoverflow上這個(gè)問(wèn)題分析的比較透徹,我這里簡(jiǎn)單的總結(jié)一下。

這里的RESOLVE("xxx")是new Promise(resolve=>resolve("xxx"))簡(jiǎn)寫

Promise.resolve("nonThenable")RESOLVE("nonThenable")類似;

Promise.resolve(thenable)RESOLVE(thenable)類似;

Promise.resolve(promise)要根據(jù)promise對(duì)象的resolve來(lái)區(qū)分,不為thenable的話情況和Promise.resolve("nonThenable")相似;

RESOLVE(thenable)RESOLVE(promise) 可以理解為 new Promise((resolve, reject) => { Promise.resolve().then(() => { thenable.then(resolve) }) })

也就是說(shuō)可以理解為Promise.resolve(thenable)會(huì)在這一次的Event Loop中立即執(zhí)行thenable對(duì)象的then方法,然后將外部的then調(diào)入下一次循環(huán)中執(zhí)行。

再形象一點(diǎn)理解,可以理解為RESOLVE(thenable).thenPROMISE.then.then的語(yǔ)法類似。

再來(lái)一道略微復(fù)雜一點(diǎn)的題加深印象

async function async1() {
    console.log("async1 start");
    await async2();
    console.log("async1 end");
}
async function async2() {
    console.log("async2");
}

console.log("script start");

setTimeout(function() {
    console.log("setTimeout");
}, 0)

async1();

new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});
console.log("script end");

題目來(lái)源

答案

/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/
let、var和const用法和區(qū)別

總結(jié)一下阮老師的介紹。

ES6 新增了let命令,用來(lái)聲明變量。它的用法類似于var,但是所聲明的變量,只在let命令所在的代碼塊內(nèi)有效。而var全局有效。

var命令會(huì)發(fā)生“變量提升”現(xiàn)象,即變量可以在聲明之前使用,值為undefinedlet命令改變了語(yǔ)法行為,它所聲明的變量一定要在聲明后使用,否則報(bào)錯(cuò)。

在代碼塊內(nèi),使用let命令聲明變量之前,該變量都是不可用的。這在語(yǔ)法上,稱為“暫時(shí)性死區(qū)”(temporal dead zone,簡(jiǎn)稱 TDZ)。

let不允許在相同作用域內(nèi),重復(fù)聲明同一個(gè)變量。

const聲明的變量不得改變值,這意味著,const一旦聲明變量,就必須立即初始化,不能留到以后賦值。const其他用法和let相同。

與這題關(guān)聯(lián)

上面代碼中,變量ivar命令聲明的,在全局范圍內(nèi)都有效,所以全局只有一個(gè)變量i。每一次循環(huán),變量i的值都會(huì)發(fā)生改變,而循環(huán)內(nèi)被賦給數(shù)組a的函數(shù)內(nèi)部的console.log(i),里面的i指向的就是全局的i。也就是說(shuō),所有數(shù)組a的成員里面的i,指向的都是同一個(gè)i,導(dǎo)致運(yùn)行時(shí)輸出的是最后一輪的i的值,也就是 10。

要是想得到預(yù)期效果,可以簡(jiǎn)單的把var換成let

iife和塊級(jí)作用域

let實(shí)際上為 JavaScript 新增了塊級(jí)作用域。

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}

上面的函數(shù)有兩個(gè)代碼塊,都聲明了變量n,運(yùn)行后輸出 5。這表示外層代碼塊不受內(nèi)層代碼塊的影響。如果兩次都使用var定義變量n,最后輸出的值才是 10。

塊級(jí)作用域的出現(xiàn),實(shí)際上使得獲得廣泛應(yīng)用的立即執(zhí)行函數(shù)表達(dá)式(IIFE)不再必要了。

// IIFE 寫法
(function () {
  var tmp = ...;
  ...
}());

// 塊級(jí)作用域?qū)懛?{
  let tmp = ...;
  ...
}
與這題的關(guān)聯(lián)

如果不用let,我們可以使用iife將setTimeout包裹,從而達(dá)到預(yù)期效果。

for (var i = 0; i < 10; i++) {
  (i =>
    setTimeout(() => {
      console.log(i);
    }, 1000))(i);
}
其他騷氣方法
for (var i = 0; i < 10; i++) {
  try {
    throw i;
  } catch (i) {
    setTimeout(() => {
      console.log(i);
    }, 1000);
  }
}
參考

阮老師es6

What"s the difference between resolve(thenable) and resolve("non-thenable-object")?

Daily-Interview-Question

并發(fā)模型與事件循環(huán)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/103503.html

相關(guān)文章

  • 深入理解JavaScript(二):一道來(lái)思考閉包

    摘要:中所有的事件綁定都是異步編程當(dāng)前這件事件沒(méi)有徹底完成,不再等待,繼續(xù)執(zhí)行下面的任務(wù)當(dāng)綁定事件后,不需要等待執(zhí)行,繼續(xù)執(zhí)行下一個(gè)循環(huán)任務(wù),所以當(dāng)我們點(diǎn)擊執(zhí)行方法的時(shí)候,循環(huán)早已結(jié)束即是最后。 概念 閉包就是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù) 點(diǎn)擊li標(biāo)簽彈出對(duì)應(yīng)數(shù)字 0 1...

    曹金海 評(píng)論0 收藏0
  • 《深入理解ES6》筆記——塊級(jí)作用綁定(1)

    摘要:沒(méi)有聲明的情況和都能夠聲明塊級(jí)作用域,用法和是類似的,的特點(diǎn)是不會(huì)變量提升,而是被鎖在當(dāng)前塊中。聲明常量,一旦聲明,不可更改,而且常量必須初始化賦值。臨時(shí)死區(qū)的意思是在當(dāng)前作用域的塊內(nèi),在聲明變量前的區(qū)域叫做臨時(shí)死區(qū)。 本章涉及3個(gè)知識(shí)點(diǎn),var、let、const,現(xiàn)在讓我們了解3個(gè)關(guān)鍵字的特性和使用方法。 var JavaScript中,我們通常說(shuō)的作用域是函數(shù)作用域,使用var聲...

    2bdenny 評(píng)論0 收藏0
  • javascript中為什么我們不能直接使用export?

    摘要:我們可以認(rèn)為,宏任務(wù)中還有微任務(wù)這里不再多做解釋可能會(huì)執(zhí)行的代碼包括腳本模塊和函數(shù)體。聲明聲明永遠(yuǎn)作用于腳本模塊和函數(shù)體這個(gè)級(jí)別,在預(yù)處理階段,不關(guān)心賦值的部分,只管在當(dāng)前作用域聲明這個(gè)變量。 相信很多人最開始時(shí)都有過(guò)這樣的疑問(wèn)假如我的項(xiàng)目目錄下有一個(gè) index.html, index.js 于是我像這樣寫 在瀏覽器之間打開index.html,發(fā)現(xiàn)showImg(https://...

    URLOS 評(píng)論0 收藏0
  • 簡(jiǎn)單理解JavaScript中的閉包

    摘要:閉包在我理解是一種比較抽象的東西。所以我寫了一篇博文來(lái)方便自己理解閉包。那么現(xiàn)在我們可以解釋一下閉包的第一個(gè)定義在計(jì)算機(jī)科學(xué)中,閉包是引用了自由變量的函數(shù)。循環(huán)中創(chuàng)建閉包在我們使用的關(guān)鍵字之前,閉包的一個(gè)常見問(wèn)題就出現(xiàn)在循環(huán)中創(chuàng)建閉包。 零. 前言 從我開始接觸前端時(shí)就聽說(shuō)過(guò)閉包,但是一直不理解閉包究竟是什么。上網(wǎng)看了各種博客,大家對(duì)閉包的說(shuō)法不一。閉包在我理解是一種比較抽象的東西。所...

    sihai 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<