寫一個回傳 Promise 物件的 Javascript function
// a.js a Promise function example
const childprocess = require("child_process"); // i.e. /usr/bin/bash
function nextTask(msg) { console.log(msg+"--- Ok ---") }
function errTask(msg) { console.log(msg+"--- Warring! ---") }
function bash(cmd) {
console.log("bash "+cmd)
return new Promise( (ok,ng) => {
childprocess.exec( cmd, (err, stdout, stderr) => err ? ng(stderr) : ok(stdout) );
})
}
async function cmd(opt ) {
console.log("副程式開始")
var shell= bash(opt) // return a Promise
await shell.then(nextTask).catch(errTask);
console.log("副程式結束")
}
console.log("主程式開始")
cmd("ls -al").then( console.log("主程式結束") )
// end of file
執行 js a.js 看輸出結果:
主程式開始
副程式開始
bash ls -al
主程式結束
total 12
drwxrwxr-x 2 mint mint 4096 9月 4 14:04 .
drwxrwxr-x 4 mint mint 4096 9月 4 13:05 ..
-rw-rw-r-- 1 mint mint 686 9月 4 14:04 a.js
--- Ok ---
副程式結束
如果將上述 Javascript 內容(a.js)做一些修改, 移除 await 之後,再執行一遍,整個過程變成:
主程式開始
副程式開始
bash ls -al
副程式結束
主程式結束
total 12
drwxrwxr-x 2 mint mint 4096 9月 4 14:05 .
drwxrwxr-x 4 mint mint 4096 9月 4 13:05 ..
-rw-rw-r-- 1 mint mint 680 9月 4 14:05 a.js
--- Ok ---
可以看到整個非同步(不定時)運作的過程,由此可以了解到 async/await 運作方式, async function 一定回傳一個稱為 Promise 的物件, 而 then( ) 是它的一個從屬函式(member function), await 就只能放在 async function 裏面, 用來等待,作為同步之用, 而 node js 的 child_process.exec 是非同步在運作(也就是說其 callback function 是隨後才會執行)的.要運用 async/await 就不得不瞭解 Promise, 因為 await 就是為了等待特定 promise 完成,才會繼續下一個動作, 但在主程序中的 async function 僅傳回 Promise 就會繼續下一步動作,並不會因 async function 內的 await 就被暫停而隔離(block),簡單就字面意義來說 async function 就是非同步的功能函式,如果要一起執行多個非同步函式又要等待某個非同步函式的完成,應該使用 Promise.all( [ , ] ) 平行處理非同步函式,避免在 await 的過程執中阻擋(block)了其它非同步函式的運作,將上述 async function 稍作一點修改:
async function multicmd( ) {
console.log("副程式開始")
var shell1= bash("ls -al") // return a Promise
var shell2= bash("pwd") // return another Promise
await shell1.then(nextTask).catch(errTask);
await shell2.then(nextTask).catch(errTask);
console.log("副程式結束")
}
console.log("主程式開始")
multicmd( ).then( console.log("主程式結束") )
這是輸出結果:
主程式開始
副程式開始
bash ls -al
bash pwd
主程式結束
total 12
drwxrwxr-x 2 mint mint 4096 9月 5 09:19 .
drwxrwxr-x 4 mint mint 4096 9月 4 13:05 ..
-rw-rw-r-- 1 mint mint 782 9月 5 09:19 a.js
--- Ok ---
/home/mint/work/kotlin
--- Ok ---
副程式結束
最後使用 async/await Promise.all 的完整範例:
const childprocess = require("child_process");
function nextTask(msg) { console.log(msg+"--- Ok ---") }
function errTask(msg) { console.log(msg+"--- Warring! ---") }
function bash(cmd) {
console.log("sh "+cmd)
return new Promise( (resolv,reject) => {
childprocess.exec( cmd, (err, stdout, stderr) => err ? reject(stderr) : resolv(stdout) ); // pipe stderr and stdout
})
}
async function multicmd( ) {
console.log("非同步副程式開始")
var promise1= bash("ls -al").then(nextTask).catch(errTask)
console.log("--- Promise1 ---")
var promise2= bash("pwd").then(nextTask).catch(errTask)
console.log("--- Promise2 .. ---")
var promise3= bash("unknow").then(nextTask).catch(errTask);
console.log("--- Promise3 .. ---")
await Promise.all([ promise1, promise2, promise3 ])
console.log("非同步副程式結束")
}
console.log("主程式開始")
multicmd( ).then(console.log("主程式結束"))
上面 promise1, promise2, promise3 不一定會依照順序輸出結果, async 用意就是將程序包裝成 Promise, 而裡面的程序若有 await 就會暫停等待結果, 一旦結果完成(呼叫 callback function 中的 reject 或 resolve )接著就會繼續往下執行直到非同步程序整個完成才會脫離 :
主程式開始
非同步副程式開始
sh ls -al
--- Promise1 ---
sh pwd
--- Promise2 .. ---
sh unknow
--- Promise3 .. ---
主程式結束
/bin/sh: 1: unknow: not found
--- Warring! ---
/home/mint/work/kotlin
--- Ok ---
total 12
drwxrwxr-x 2 mint mint 4096 9月 6 09:23 .
drwxrwxr-x 4 mint mint 4096 9月 4 13:05 ..
-rw-rw-r-- 1 mint mint 957 9月 6 09:23 a.js
--- Ok ---
非同步副程式結束
沒有留言:
張貼留言