提醒
若node.js的執行過程中,發生上圖的錯誤,就會造成整個網站後台crash,後面的程式就不會繼續執行了。為了避免這種情況,可以使用 try...catch...
語法,捕捉錯誤的程式碼。
舉例來說:
function func(){
return new Promise((resolve, reject)=>{
setTimeout(function(){
resolve(Math.random())
}, 500)
})
}
func()
.then(r=>{
info.innerHTML += `<p>${r}</p>`;
return func();
})
.then(r=>{
info.innerHTML += `<p>${r}</p>`;
})
console.log('ooo')
const str = '{"a":1,"b":"ben}'
let obj = JSON.parse(str)
console.log('kkk')
- promise會執行
-
console.log('ooo')
會執行 -
JSON.parse(str)
出現錯誤 -
console.log('kkk')
便被中斷,不會執行了 - 合理推測javascript底層是多個執行序在執行
如果是這樣寫的話,就連promise也不會執行到,因為被中間的錯誤javascript所截止中斷了。
console.log('ooo')
const str = '{"a":1,"b":"ben}'
let obj = JSON.parse(str)
console.log('kkk')
function func(){
return new Promise((resolve, reject)=>{
setTimeout(function(){
resolve(Math.random())
}, 500)
})
}
func()
.then(r=>{
info.innerHTML += `<p>${r}</p>`;
return func();
})
.then(r=>{
info.innerHTML += `<p>${r}</p>`;
})
使用 try... catch...
的寫法:
console.log('ooo')
const str = '{"a":1,"b":"ben}'
let obj = {};
try {
obj = JSON.parse(str)
console.log('-------')
} catch (ex) {
console.log('ex:',ex)
} finally {
console.log('try catch finally')
}
console.log('kkk')
console.log(obj)
JSON.stringify
<body>
<div id="info"></div>
<script>
const p1 = {
name: 'Ben',
age: 18
}
const p2 = {
name: 'David',
age: 25
}
p1.next = p2
info.innerHTML = JSON.stringify(p1);
</script>
</body>
執行結果: {"name":"Ben","age":18,"next":{"name":"David","age":25}}
其中,next
變成p1
的一個屬性。
若程式改為如下:
<body>
<div id="info"></div>
<script>
const p1 = {
name: 'Ben',
age: 18
}
const p2 = {
name: 'David',
age: 25
}
const p3 = {
name: 'Peter',
age: 26
}
p1.next = p2
p2.next = p3
info.innerHTML = JSON.stringify(p1);
</script>
</body>
執行結果為: {"name":"Ben","age":18,"next":{"name":"David","age":25,"next":{"name":"Peter","age":26}}}
現在問題是,若再加上這一段程式: p3.next = p1
,這樣就變成繞圈圈了。
如果先把 info.innerHTML = JSON.stringify(p1);
拿掉,則程式為:
<body>
<div id="info"></div>
<script>
const p1 = {
name: 'Ben',
age: 18
}
const p2 = {
name: 'David',
age: 25
}
const p3 = {
name: 'Peter',
age: 26
}
p1.next = p2
p2.next = p3
p3.next = p1
// info.innerHTML = JSON.stringify(p1);
</script>
</body>
在瀏覽器的執行結果為:
結果為沒有錯誤,而且使用console去取值都是正常。
其結構為圈圈狀的結構。
這樣圈圈裝的結構如果要使用語法 info.innerHTML = JSON.stringify(p1);
將之轉換為字串,就會出錯。
另一個promise的例子
<body>
<div id="info">
<p>123</p>
</div>
<script>
function func(msec){
return new Promise((resolve, reject)=>{
setTimeout(function(){
resolve(Math.random()*msec)
}, msec)
})
}
const ar=[];
func(800)
.then(r=>{
ar.push(r);
return func(700);
})
.then(r=>{
ar.push(r);
return func(800);
})
.then(r=>{
ar.push(r);
info.innerHTML += JSON.stringify(ar);
}
)
</script>
</body>
執行結果:
其實以上還是callback function,只是傳統的callback function會凹進去,現在只是拉平,只是在程式碼維護管理會比較方便。
現在要在進一步作簡化,嘗試把以下程式碼包裝成一個function:
const ar=[];
func(800)
.then(r=>{
ar.push(r);
return func(700);
})
.then(r=>{
ar.push(r);
return func(800);
})
.then(r=>{
ar.push(r);
info.innerHTML += JSON.stringify(ar);
}
所以程式碼如下:
<body>
<div id="info">
<p>123</p>
</div>
<script>
function func(msec) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(Math.random() * msec)
}, msec)
})
}
function doSomething() {
const ar = [];
func(800)
.then(r => {
ar.push(r);
return func(700);
})
.then(r => {
ar.push(r);
return func(800);
})
.then(r => {
ar.push(r);
// info.innerHTML += JSON.stringify(ar);
return ar;
})
}
const br = doSomething();
</script>
</body>
以上程式碼, br
無法取得 return
的 ar
,因為
func(800)
.then(r => { .....
以下的程式是非同步的, function doSomething() {...
是同步的,一下子就跑完了,所以不會等 ar
的 return
,所以 br
會取到空值。
若在程式插入一些識別的記號,程式改寫如下:
<body>
<div id="info">
<p>123</p>
</div>
<script>
function func(msec) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(Math.random() * msec)
}, msec)
})
}
function doSomething() {
console.log(1)
const ar = [];
func(800)
.then(r => {
console.log(2)
ar.push(r);
return func(700);
})
.then(r => {
ar.push(r);
return func(800);
})
.then(r => {
ar.push(r);
// info.innerHTML += JSON.stringify(ar);
return ar;
})
console.log(3)
}
const br = doSomething();
console.log('br:',br)
</script>
</body>
那麼程式執行的結果為:
所以br不會取得結果。
這個問題要用 async
await
來解決,這是屬於ES7的語法。
所以上面的程式改寫如下:
<body>
<div id="info">
<p>123</p>
</div>
<script>
function func(msec) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(Math.random() * msec)
}, msec)
})
}
async function doSomething() {
console.log(1)
const ar = [];
ar.push(await func(800));
console.log(2)
ar.push(await func(700));
ar.push(await func(600));
console.log(3)
return ar;
}
const br = doSomething();
console.log('br:', br)
</script>
</body>
這樣的寫法, br
同樣無法取得資料。
先說明一下:
- 使用
async
宣告function
,裡面await
後面接的必須是promise物件
,這是屬於非同步的操作 -
await
必須在一個由async
宣告的function
裡面 (這是規定) -
async function
看起來是同步的,但其底層是非同步的。 -
async
包起來的function
,也會變成promise
-
async await
是建立在promise
的基礎之上,如果沒有promise
的語法程式,就不能使用async await
了
OK,既然 async function doSomething(){}
變成promise
,那麼程式可改寫如下:
<body>
<div id="info"></div>
<script>
function func(msec) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(Math.random() * msec)
}, msec)
})
}
async function doSomething() {
console.log(1)
const ar = [];
ar.push(await func(800));
console.log(2)
ar.push(await func(700));
ar.push(await func(600));
console.log(3)
return ar;
// info.innerHTML += JSON.stringify(ar);
}
doSomething()
.then(a=>{
info.innerHTML += JSON.stringify(a);
})
</script>
</body>
執行結果為:
使用匿名函式來寫:
<body>
<div id="info"></div>
<script>
function func(msec) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve(Math.random() * msec)
}, msec)
})
}
async function doSomething() {
console.log(1)
const ar = [];
ar.push(await func(800));
console.log(2)
ar.push(await func(700));
ar.push(await func(600));
console.log(3)
return ar;
// info.innerHTML += JSON.stringify(ar);
}
let br = [];
(async ()=>{
br = await doSomething();
console.log('br:',br);
})();
</script>
</body>
執行結果為: