控制流程是 JavaScript 解譯器的執行順序 聲明。如果某個指令碼不包含改變其流程的陳述式, 且一次只能執行一行控制項結構是 用於判斷某組陳述式是否會根據 定義一組條件、重複執行一組陳述式,或打斷 陳述式序列。
條件陳述式
條件陳述式會根據一或多個項目,決定是否應執行程式碼。
再加入一些條件如果
系統會將相關條件 (或一組條件) 的評估結果視為 true
。否則,
程式碼就會略過
if
……else
if
陳述式會評估相符括號內的條件,
後續追蹤。如果括號內的條件評估為 true
,
陳述或區塊陳述
系統會執行以下比對:
if ( true ) console.log( "True." );
> "True."
if ( true ) {
const myString = "True.";
console.log( myString );
}
> "True."
如果括號內的條件評估為 false
,
,系統將忽略此屬性:
if ( false ) console.log( "True." );
else
關鍵字緊接在 if
陳述式之後
有條件執行的陳述式
if
條件評估為 false
:
if ( false ) console.log( "True." )''
else console.log( "False" );
> "False."
如要將多個 if
陳述式鏈結在一起,可以使用
有條件執行的陳述式,在 else
的另一個 if
陳述式之後:
const myCondition = 2;
if ( myCondition === 5 ) console.log( "Five." );
else if ( myCondition === 2 ) console.log( "Two." );
強烈建議在條件式後方使用區塊陳述式語法,
提高可讀性,但 else if
子句通常是例外狀況:
if ( myCondition === 5 ) {
console.log( "Five." );
} else if ( myCondition === 3 ) {
console.log( "Three" );
} else {
console.log( "Neither five nor three." );
}
> "Neither five nor three."
三元運算子
if
有條件地執行陳述式。三元運算子 (更準確)
但較不常見的「三元條件運算子」) 是簡寫
有條件地執行運算式顧名思義,
運算子是唯一使用三個運算元的 JavaScript 運算子:
- 要評估的條件,後面加上問號 (
?
)。 - 條件評估為
true
時,要執行的運算式,後接 冒號 (:
)。 - 條件評估為
false
時要執行的運算式。
經常用於有條件地設定或傳遞值:
const myFirstResult = true ? "First value." : "Second value.";
const mySecondResult = false ? "First value." : "Second value.";
myFirstResult;
> "First value."
mySecondResult;
> "Second value."
switch
……case
使用 switch
陳述式,比較運算式與一組結果清單的值
使用一或多個 case
關鍵字所定義的潛在值。這個語法
原因是它來自 JavaScript 早期設計決策。
switch
...case
語法使用 switch
關鍵字,後面加上運算式,可達到以下目的:
然後以括號括住,後面加上一組相符的大括號。
switch
的內文可包含 case
個關鍵字,通常可包含一或多個。
後面接著運算式或值,並在後面加上冒號 (:
)。
當解譯器抵達的 case
時,其值符合
它會在 switch
關鍵字之後使用
陳述式參照 case
子句後:
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "True."
系統會執行相符 case
後的所有陳述式,即使
包含在區塊陳述式中。
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
let myVariable = "True.";
console.log( myVariable );
}
> "True."
使用 switch…case
的一個問題是,找到相符項目後,
JavaScript 解譯器會執行符合 case
的「任何」陳述式,
甚至是其他 case
子句中的數量這就是所謂的「流向」加入
下 case
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "False."
> "True."
為了避免出現落後情況,請在所有案例結尾加上 break
關鍵字,
立即停止評估 switch
主體:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
break;
case true:
console.log( "True." );
break;
}
> "False."
如果沒有與條件值相符的 case
,switch
會選取 default
子句 (如果有的話):
switch ( 20 ) {
case 5:
console.log( "The value was five." );
break;
case 10:
console.log( "The value was ten." );
break;
default:
console.log( "The value was something unexpected." );
}
> "The value was something unexpected."
然而,下降也適用於 default
,進而可能導致
非預期的結果如要解決這個問題,請在 default
陳述式結尾加上 break
,
或放在案件清單的最後
switch ( 20 ) {
default:
console.log( "The value was something unexpected." );
case 10:
console.log( "The value was ten." );
break;
case 5:
console.log( "The value was five." );
break;
}
> The value was something unexpected.
> The value was ten.
由於 case
子句不需要
分組的區塊陳述式
多個陳述式,case
和 default
子句不會建立
詞法範圍:
let myVariable;
switch ( true ) {
case true:
let myVariable = "True.";
break;
default:
let myVariable = "False.";
break;
}
> Uncaught SyntaxError: redeclaration of let myVariable
如要管理範圍,請使用區塊陳述式:
let myVariable;
switch ( true ) {
case true: {
let myVariable = "True.";
break;
}
default: {
let myVariable = "False.";
break;
}
}
迴圈和疊代
迴圈可讓您重複一組陳述式,只要符合條件即可。 直到符合條件為止使用迴圈執行一組固定的指示 次數、直到特定結果完成或到翻譯完成為止 達到可疊代資料結構的末端 (例如 陣列、地圖或集合、物件的最終屬性,或 字串)。
循環中斷「由上至下」將指令碼的執行流程疊代 直到符合一或多個條件 視用於建立迴圈的語法而定。循環播放結束後 執行作業會接續後續的陳述式。在以下範例中 迴圈內文中的陳述式會在 翻譯移至下列位置:
let iterationCount = 0;
console.log( "Pre-loop." );
while( iterationCount < 3 ) {
iterationCount++;
console.log( "Loop iteration." );
}
console.log( "Continuing on." );
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Continuing on."
如果在迴圈執行期間無法滿足條件,迴圈會繼續 無限期。這些「無限迴圈」是常見的程式設計問題, 會導致主要執行執行緒 即可無限期暫停,甚至讓瀏覽器分頁當機。
以下範例會在布林值 true
保持不變的情況下持續執行
true
。由於布林值不可變動,
即可建立無限迴圈
console.log( "Pre-loop." );
while( true ) {
console.log( "Loop iteration." );
}
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
…
避免在正式版程式碼中留下無限迴圈。不小心 只要在開發期間關閉執行中的瀏覽器分頁,即可解決這個問題 更新程式碼,讓迴圈不再是無限可能,只要重新開啟 頁面。
while
會建立 while
迴圈,方法是使用 while
關鍵字,後面加上一對
相符括號包含要評估的條件。如果指定
條件最初評估為 true
,陳述式 (或
區塊陳述式) 後方,
系統就會執行這些括號如果不是,迴圈將一律不會執行。在每個
系統會重新評估條件,如果仍為 true
,則迴圈
重複執行。
let iterationCount = 0;
while( iterationCount < 3 ) {
iterationCount++;
console.log( `Loop ${ iterationCount }.` );
}
> "Loop 1."
> "Loop 2."
如果解譯器在 while
迴圈中找到 continue
陳述式,就會停止
反覆調整、重新評估條件,並盡可能持續循環:
let iterationCount = 0;
while( iterationCount <= 5 ) {
iterationCount++;
if( iterationCount === 3 ) {
continue;
}
console.log( `Loop ${ iterationCount }.` );
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Loop 4."
> "Loop 5."
> "Loop ended."
如果解譯器在 while
迴圈中找到 break
陳述式,表示該疊代
而系統也不會重新評估條件,讓翻譯模式繼續:
let iterationCount = 1;
while( iterationCount <= 5 ) {
if( iterationCount === 3 ) {
console.log(`Iteration skipped.``);`
break;
}
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Iteration skipped.
> "Loop ended."
您可以使用 while
疊代指定次數,如
先前範例,但 while
最常見的用途是
不確定長度:
let randomize = () => Math.floor( Math.random() * 10 );
let randomNum = randomize();
while( randomNum !== 3 ){
console.log( `The number is not ${ randomNum }.` );
randomNum = randomize();
}
console.log( `The correct number, ${ randomNum }, was found.` );
> "The number is not 0."
> "The number is not 6."
> "The number is not 1."
> "The number is not 8."
> "The correct number, 3, was found."
do
……while
do
...while
是 while
迴圈的變化版本,其中有條件式
評估會在每次迴圈疊代的「結尾」發生。也就是說,
迴圈主體一律至少執行一次
如要建立 do
...while
迴圈,請使用 do
關鍵字,後面加上陳述式
(或封鎖聲明)
每次迴圈疊代時都會執行。緊接該敘述後,加入
while
和相符的括號,包含待評估的條件。時間
此條件不再評估為 true
,迴圈結束。
let iterationCount = 1;
do {
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
} while ( iterationCount < 3 );
> "Loop 1."
> "Loop 2."
> "Loop 3."
與 while
迴圈相同,do
...while
是最常見的用途,也就是
不確定長度:
let randomNum;
do {
randomNum = ( () => Math.floor( Math.random() * 10 ) )();
console.log( `Is the number ${ randomNum }?` );
} while ( randomNum !== 3 );
console.log( `Yes, ${ randomNum } was the correct number.` );
> "Is the number 9?"
> "Is the number 2?"
> "Is the number 8?"
> "Is the number 2?"
> "Is the number 3?"
> "Yes, 3 was the correct number."
for
使用 for
迴圈疊代處理已知數量。在舊版程式碼集中,這個程式碼
經常用於疊代陣列中的元素
如要建立 for
迴圈,請使用 for
關鍵字,後面加上一組括號
可接受以下三個運算式,依序使用
分號:
- 迴圈開始時評估的運算式
- 決定迴圈是否應繼續的條件
- 在每個迴圈結束時執行的運算式
然後在括號後方加上陳述式 (通常是 封鎖陳述式) 會在迴圈中執行。
for( let i = 0; i < 3; i++ ) {
console.log( "This loop will run three times.")
}
第一個運算式會初始化一個變數,做為計數器。這個
運算式會在第一次疊代之前,評估一次。你可以
比照任何其他做法,使用 let
(或以往的 var
) 初始化這個變數
變數,且範圍是迴圈的主體。這些變數可以包含
有效 ID,但經常稱為 i
,用於「疊代」或「索引」
這似乎與既定成果相牴觸
可預測 ID 名稱的最佳做法
但慣例已經建立好,可以讓其他開發人員
內容。由於已建立索引的集合不會編入索引,
這些變數的初始值為 0
。
與其他形式的迴圈相同,條件就是決定
是否應執行迴圈通常用來設定
疊代計數器的 bound。解譯器會先評估
第一次執行 for
迴圈。如果條件起初並未執行
評估為 true
,則不會執行迴圈主體。
每次疊代時,都會在迴圈結束時執行最終運算式。 通常用於將 ID 遞增 1。
您最常看到 for
迴圈會在較舊的陣列中疊代
程式碼集在這些情況下,繼續迴圈的指定條件為
疊代次數小於或等於要疊代的陣列長度
。這個變數會用來追蹤目前疊代次數
增加陣列中與該索引相關聯的值,讓每個元素
要依序處理的陣列:
var myArray = [ true, false, true ];
for( let i = 0; i <= myArray.length; i++ ) {
console.log( myArray[ i ] );
}
> true
> false
> true
此方法已遭到捨棄,已改用更現代化的做法, 循環處理可疊代資料結構。
for
[...] of
[...]
使用 for
...of
... 迴圈疊代儲存在
可疊代資料結構,例如陣列、集合或地圖。
for
...of
... 迴圈使用 for
關鍵字,後面加上一組括號
包含變數,後方依序加上 of
,接著系統就會疊代資料結構
。變數可以是這裡使用 let
、const
或
var
,這是之前在目前範圍內宣告的變數,物件
或是其執行個體
解構作業。
其中包含與目前疊代相對應的元素值
迴圈結構
const myIterable = [ true, false, true ];
for( const myElement of myIterable ) {
console.log( myElement );
}
> true
> false
> true
在此範例中,針對 myElement
使用 const
即使 myElement
是
並在每次迴圈疊代時提供新的值這是因為變數
使用 let
或 const
宣告的範圍限定在
迴圈這個變數會在每次疊代時初始化,並在
我們再決定疊代的部分
for
...in
...
使用 for
...in
... 迴圈以疊代物件的列舉屬性。
包括列舉的繼承屬性就像使用 for
...of
迴圈一樣,
for
...in
...迴圈使用 for
關鍵字,後面加上一組括號
包含變數 (即對應屬性鍵值的變數)
與目前循環的疊代相同這個變數後面會加上
in
關鍵字,然後要疊代的物件:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
console.log( myKey );
}
> "myProperty"
> "mySecondProperty"
同樣地,儘管 myKey
的值會隨著每次迴圈疊代而改變,
您可以使用 const
而不會發生錯誤,因為這項變數實際上被捨棄
然後在每次疊代時重新建立。
與每個屬性鍵相關聯的值不會直接提供給
for
...in
...語法。不過,由於迴圈可存取
您就能利用該鍵「查詢」指定的值:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "mySecondProperty : false"
繼承自內建建構函式的屬性不可為列舉,表示
for
...in
... 不會透過繼承自 Object
的屬性疊代
建構函式中設定。不過,物件中任何的可列舉屬性
原型鏈包含:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "protoProperty : true"
JavaScript 提供的內建方法可判斷屬性是否為
物件的直接屬性,而非物件原型上的屬性
鏈結:modern
Object.hasOwn()
和舊版 Object.prototype.hasOwnProperty()
方法。這些
方法會評估指定屬性是否為繼承 (或未宣告)
僅針對指定物件的即時屬性傳回 true
:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
if ( Object.hasOwn( myObject, myKey ) ) {
console.log( `${ myKey } : ${ myValue }` );
}
}
> "myProperty : true"
另外有三種靜態方法,每個方法都會傳回由
物件的列舉鍵 (Object.keys()
)、值 (Object.values()
),或
鍵/值組合 (Object.entries()
):
const myObject = { "myProperty" : true, "mySecondProperty" : false };
Object.keys( myObject );
> Array [ "myProperty", "mySecondProperty" ]
這可讓您疊代物件鍵、值或鍵/值組合 (使用 解構作業)。 在不加入該物件原型擁有的屬性的情況下:
const myPrototype = { "protoProperty" : "Non-enumerable property value." };
const myObject = Object.create( myPrototype, {
myProperty: {
value: "Enumerable property value.",
enumerable: true
}
});
for ( const propKey of Object.keys( myObject ) ) {
console.log( propKey );
}
> "myProperty"
for ( const propValue of Object.values( myObject ) ) {
console.log( propValue );
}
> "Enumerable property value."
for ( const [ propKey, propValue ] of Object.entries( myObject ) ) {
console.log( `${ propKey } : ${ propValue }` );
}
> "myProperty : Enumerable property value."
forEach()
陣列提供的 forEach()
方法。
地圖、設定、
NodeList 建構函式很適合用來疊代資料
回呼函式採用的結構。不同於其他形式的迴圈
無法透過任何 forEach()
方法建立的迴圈,無法使用 break
或
continue
。
forEach
是每個資料結構原型擁有的方法。每forEach
方法預期回呼函式將做為引數,但這兩者有些微差異
。第二個 (選用)
引數會指定 this
值,做為叫用結構定義的
回呼函式。
與 Array.forEach
搭配使用的回呼函式可提供包含
目前元素的值、目前元素的索引,以及叫用 forEach
方法的陣列:
const myArray = [ true, false ];
myArray.forEach( ( myElement, i, originalArray ) => {
console.log( i, myElement, originalArray );
});
> 0 true Array(3) [ true, false ]
> 1 false Array(3) [ true, false ]
搭配 Map.forEach
使用的回呼函式提供包含
與目前元素相關聯的值,即與目前元素相關聯的鍵
元素,以及叫用 forEach
方法的 Map,如下所示:
const myMap = new Map([
['myKey', true],
['mySecondKey', false ],
]);
myMap.forEach( ( myValue, myKey, originalMap ) => {
console.log( myValue, myKey, originalMap );
});
> true "myKey" Map { myKey → true, mySecondKey → false }
> false "mySecondKey" Map { myKey → true, mySecondKey → false }
Set.forEach
回呼包含類似的參數。由於 Set 沒有
索引或鍵與值不同,第二個引數會提供
多餘、可忽略的值,嚴格遵循語法與
其他 forEach
方法。
const mySet = new Set([ true, false ]);
mySet.forEach( ( myValue, myKey, originalSet ) => {
console.log( myValue, myKey, originalSet );
});
> true true Set [ true, false ]
> false false Set [ true, false ]
迭代器
可疊代是指由個別元素組成的任何資料結構,可傳回
反覆使用先前介紹的方法疊代器是
遵循疊代器通訊協定的可疊代物件,代表該物件必須
逐一進階的 next()
方法;該方法一次只會有一個元素。
因此每次呼叫該方法時,都會針對每個序列傳回一個物件
特定格式的
JavaScript 內建的可疊代資料結構 (例如
Array、
Map 和
Set) 不是疊代器,且
但會繼承 iterator
方法 (使用
@@iterator
知名符號,
這樣會傳回從可疊代資料結構建立的疊代器物件:
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterable;
> (3) [1, 2, 3]
myIterator;
> Array Iterator {}
對疊代器呼叫 next()
方法,逐步執行其元素
一次包含一個物件,而每個呼叫都傳回一個包含兩個
屬性:value
,內含目前元素的值;以及
done
是一個布林值,用來指出疊代器是否已在
資料結構只有在呼叫 next()
時,done
的值才會是 true
會導致系統嘗試存取
iterator。
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: undefined, done: true }
產生器函式
使用 function*
關鍵字 (注意星號) 即可宣告產生器
函式,或是定義產生器函式運算式:
function* myGeneratorFunction() { };
與疊代器一樣,產生器函式可維持狀態。呼叫 產生器函式會傳回新的 Generator 物件,但不會立即傳回 執行函式主體中的程式碼:
function* myGeneratorFunction() {
console.log( "Generator function body ")
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject;
> Generator { }
typeof myGeneratorObject;
> "object"
產生器物件遵循疊代器通訊協定。每次呼叫
產生器函式傳回的 next()
是由 yield
運算式決定。
這會暫停執行產生器函式,並將
包含 yield
關鍵字的運算式。稍後呼叫 next()
繼續執行函式,在下一個 yield
運算式暫停,並
傳回相關聯的值。
function* myGeneratorFunction() {
yield "My first yielded value.";
yield "My second yielded value.";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: "My first yielded value.", done: false }
myGeneratorObject.next();
> Object { value: "My second yielded value.", done: false }
在未使用 yield
指定其他值後呼叫 next()
時,
return
或 throw
(發生錯誤時),函式的其餘部分
會執行主體,而傳回的物件的 value
為 undefined
和 done
true
的資源:
function* myGeneratorFunction() {
console.log( "Start of the generator function." );
yield "First";
console.log( "Second part of the generator function." );
yield "Second";
console.log( "Third part of the generator function." );
yield "Third";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> "Start of the generator function."
> Object { value: "First", done: false }
myGeneratorObject.next();
> "Second part of the generator function."
> Object { value: "Second", done: false }
myGeneratorObject.next();
> "Third part of the generator function."
> Object { value: "Third", done: false }
myGeneratorObject.next();
> Object { value: undefined, done: true }
請只在產生器函式傳回的物件上使用 next()
,不要使用
編碼器-解碼器函式本身否則,每次對產生器函式的呼叫
建立新的產生器物件:
function* myGeneratorFunction() {
yield "First";
yield "Second";
};
myGeneratorFunction().next();
> Object { value: "First", done: false }
myGeneratorFunction().next();
> Object { value: "First", done: false }
與任何函式一樣,產生器函式會在遇到 return
時暫停
字詞。然後它會將物件傳回至叫用的結構定義,其中包含
傳回的值以及值為 true
的 done
屬性。
function* myGeneratorFunction() {
yield 1;
yield 2;
return 3;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next().done;
> Object { value: 1, done: false }
myGeneratorObject.next().done;
> Object { value: 2, done: false }
myGeneratorObject.next();
> Object { value: 3, done: true }
yield
運算式可採用 ID 的部分語意
允許雙向的「溝通」從三個可解決的廣告請求中
產生器的功能當值傳遞至產生器的 next()
方法,如
引數,就會取代與先前暫停的
yield
運算式:
function* myGeneratorFunction() {
const firstYield = yield;
yield firstYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
請注意,這取代了與
而且不只是將前一個 yield
的值重新指派給yield
在 next()
中指定的值:
function* myGeneratorFunction() {
const firstYield = yield;
const secondYield = yield firstYield + 100;
yield secondYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 10 ); // Can be thought of as changing the value of the `firstYield` variable to `10
> Object { value: 110, done: false }
myGeneratorObject.next( 20 ); // Can be thought of as changing the value of the `secondYield` variable to `20`, _not_ `20 + 100;`
> Object { value: 30, done: false }
傳遞至 next()
第一個呼叫的引數會忽略任何引數,因為沒有任何引數
上一個 yield
運算式接受該值。和其他函式一樣
傳遞至初始產生器函式呼叫的引數
產生器函式主體的範圍:
function* myGeneratorFunction( startingValue ) {
let newValue = yield startingValue + 1;
newValue = yield newValue + 10;
yield startingValue + 20;
};
const myGeneratorObject = myGeneratorFunction( 2 );
myGeneratorObject.next( 1 );
> Object { value: 3, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
myGeneratorObject.next( 10 );
Object { value: 22, done: false }
yield*
(請注意星號) 運算子會與可疊代項目搭配使用,例如
另一個產生器函式來反覆執行,然後產生每個值的運算元
會傳回:
function* mySecondaryGenerator() {
yield 2;
yield 3;
}
function* myGenerator() {
yield 1;
yield* mySecondaryGenerator();
yield 4;
return 5;
}
const myIterator = myGenerator();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: 4, done: false }
myIterator.next();
> Object { value: 5, done: true }
非同步 JavaScript
雖然 JavaScript 基本上是同步性質 但有一些機制可讓開發人員運用這些機制 要執行的事件迴圈 非同步作業
Promise
Promise 是一個預留位置,但該值在保證為 已建立。這個容器可以指定非同步作業 檢查作業是否成功或失敗 陣列的值,再加上產生的值。
使用 new
運算子和內建 Promise
建立 Promise 執行個體
建構函式函數。這個建構函式接受名為「執行器」的函式
做為引數這個執行程式函式通常用於
非同步動作,然後指定 Promise 的
視為成功完成或遭到拒絕Promise 的定義為「待處理」
執行期間。執行程式完成後,會出現一個 Promise
表示屬於「可填入內容」 (在部分說明文件來源中,則是「已解決」)
執行函式所執行的非同步動作
如果執行工具函式發生錯誤,則成功,或 rejected。
執行的非同步動作失敗Promise 實現或
系統會視為「已設定」。
const myPromise = new Promise( () => { });
建構函式會使用兩個引數呼叫執行程式函式。這些引數 可用來手動執行或拒絕 Promise:
const myPromise = new Promise( ( fulfill, reject ) => { });
用於執行或拒絕 Promise 的函式會呼叫 Promise, Promise 值做為引數 (通常是拒絕錯誤):
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was successful." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 10000);
});
myPromise;
> Promise { <state>: "pending" }
myPromise;
> Promise { <state>: "fulfilled", <value>: "This Promise was successful." }
Promise 鏈結
產生的 Promise 物件可使用 then()
、catch()
和
繼承自 Promise 建構函式的 finally()
方法。每個
方法會傳回 Promise,立即使用 then()
採取行動。
catch()
,或再次使用 finally()
,讓您「鏈結」產生的 Promise。
then()
提供兩個回呼函式做為引數。使用第一個項目完成
產生的 Promise,並以第二個方式拒絕該 Promise這兩種方法都接受
引數,為產生的 Promise 值提供值。
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise.then( successfulResult => console.log( successfulResult ), failedResult => console.error( failedResult ) );
> "This Promise was successful."
您也可以使用 then()
只處理完成的狀態,而 catch
則可
處理遭拒狀態呼叫 catch
,並使用包含
Promise 拒絕方法中提供的值:
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = false;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise
.then( fulfilledResult => console.log(fulfilledResult ) )
.catch( rejectedResult => console.log( rejectedResult ) )
.finally( () => console.log( "The Promise has settled." ) );
> "Error: This Promise has been rejected."
> "The Promise has settled."
與 then
和 catch
不同,後者可在 Promise 執行時執行處理常式函式
執行或拒絕時,就會做為引數傳遞至 finally
的函式
方法,無論 Promise 已完成或遭到拒絕,系統都會呼叫此方法。
呼叫處理常式函式時沒有引數,因為該函式的用途不是
處理從 Promise 傳送的值,但只會在
Promise 已完成。
並行
Promise 建構函式提供四種方法,可以同時處理多個相關的
Promise,使用包含 Promise 物件的可疊代。這些
每個方法都會傳回一個 Promise,而根據狀態,系統會執行或拒絕
。例如,Promise.all()
可建立 Promise
請依照所有 Promise 傳遞至該方法才執行以下動作:
const firstPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const secondPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const thirdPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const failedPromise = new Promise( ( fulfill, reject ) => reject( "Failed.") );
const successfulPromises = [ firstPromise, secondPromise, thirdPromise ];
const oneFailedPromise = [ failedPromise, ...successfulPromises ];
Promise.all( successfulPromises )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> Array(3) [ "Successful. ", "Successful. ", "Successful. " ]
Promise.all( oneFailedPromise )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> "Failed."
Promise 並行方法如下:
Promise.all()
- 只有在所有提供的 Promise 都完全符合的情況下,才算完成。
Promise.any()
- 若提供的任一 Promise 符合,且僅遭拒,就會自動填入 如果所有 Promise 都遭到拒絕
Promise.allSettled()
- 無論結果為何,在 Promise 解決後就完成。
Promise.race()
- 根據第一份承諾書的結果拒絕或完成。 忽略所有稍後解決的 Promise。
async
/await
當您在函式宣告之前使用 async
關鍵字
或函式運算式,任何
函式傳回的值會視為完成的 Promise,
值。讓您以相同的方式執行及管理非同步作業
以及同步開發工作流程
async function myFunction() {
return "This is my returned value.";
}
myFunction().then( myReturnedValue => console.log( myReturnedValue ) );
> "This is my returned value."
await
運算式會暫停執行非同步函式,
相關聯的 Promise 已設定完成設定好 Promise 之後,
await
運算式是 Promise 的執行或遭拒值。
async function myFunction() {
const myPromise = new Promise( ( fulfill, reject ) => { setTimeout( () => fulfill( "Successful. "), 5000 ); });
const myPromisedResult = await myPromise;
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "Successful."
await
運算式中包含的所有非 Promise 值都會傳回為
完成承諾:
async function myFunction() {
const myPromisedResult = await "String value.";
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "String value."
隨堂測驗
您會使用哪種迴圈來疊代已知數量?
for
do...while
while