Ajax 板


LINE

Promise 無法解決你的問題,就如一樓所說,你必須把賦值的動作移到 callback 函數內。Promise 是一種用來解決多層 callback 的工具。 先瞭解 JavaScript 的 callback(回呼函數)。 JavaScript 中,有些異步函式會要求你給它一個 callback,如 setTimeout。 當操作完成的時候(對 setTimeout 來說,就是計時器時間到的時候),callback 就會被呼叫。以你的程式為例︰ var x; function getValue(){ var temp; // temp 沒有值,為 undefined setTimeout( function(){temp = 3}, // 這個函式在 2 秒後才會被呼叫 2000 ); return temp // 由於前述的原因,temp 還是 undefined } x = getValue(); // 由 getValue 回傳的值,undefined 過了兩秒後,setTimeout 內的 function 被呼叫,把 getValue 內的 temp 設為 3, 但這不影響外面的 x。如果要正確取得兩秒後 getValue 的回傳值,你也必須把 getValue 也設計成使用 callback 的型式︰ var x; function getValue(done) { // done 是外部傳來的 callback var temp; setTimeout( function(){ temp = 3; done(temp); // 在完成操作後呼叫 callback,並把值傳進去 }, 2000 ); } getValue(function(value) { // getValue 已經變成非同步函式了,這個 function // 會在 getValue 操作完成時被呼叫 x = value; console.log(x) // x 已被賦值,可以對 x 操作 }); 如此一來,getValue 也變成了一個異步函數,和 setTimeout 一樣。 問題來了,假如你要多次使用異步函數,callback 就會變成很多層…… var x, y; // 省略 getValue 的定義,和上方相同 getValue(function(value) { x = value; // 以非同步(callback)獲得 getValue 的回傳值後,再呼叫一次 // 以獲得第二個值 getValue(function(value) { y = value; // 獲得第二個值 console.log(x, y); // 這時 x, y 都已經取得了,可以開始你想要的操作 }); }); 那呼叫 100 次豈不是要敲 tab 鍵(縮排)一百次?於是有人想到了用 queue 來儲存 callback,再依序呼叫︰ var x, y; function queueAsyncCaller(queue) { // 接受一個非同步函數陣列 function dequeue() { var asyncFunction = queue.shift(); // 依序執行 if (asyncFunction) { asyncFunction(dequeue); // 當 asyncFunction 操作完成時,會進行下一次的 // dequeue } } dequeue(); } queueAsyncCaller([ function(done) { getValue(function(value) { // 所有的 getValue 都在非同步函數中執行 x = value; done(); }); }, function(done) { getValue(function(value) { y = value; done(); }); }, function() { console.log(x, y); } ]); 如此一來,一層層的 callback 就被「攤平」成一個 callback「鍊」。 Promise 就是建立在這種思想上的。但是 * Promise 的 callback 不是在一開始以 array 儲存,而是以 .then() 動態新增 * Promise 的 callback (.then) 可以回傳一個 Promise,也就是說 Promise 鍊 可以動態新增 * Promise 並非只接受 done() 一個 callback,而可以根據狀況 resolve() 或 reject() 如果把 getValue 以 Promise 改寫的話︰ function getValue() { // getValue 現在不接受 callback // 而是回傳一個 Promise 物件,可以用 .then 動態新增 callback return new Promise(function(resolve, reject) { var temp; setTimeout(function() { temp = 3; resolve(temp); // 兩秒後操作完成,將回傳值送給 resolve() }, 2000); }); } var x, y; getValue() // 建立 getValue Promise .then(function(value) { // 設定 callback x = value; return getValue(); // 再插入一個 getValue 進 Promise 鍊 }) .then(function(value) { // 設定 callback y = value; }) .then(function() { console.log(x, y); }); 還要再精簡的話,可以使用 async/await(前幾天的 Firefox 52 已經可以用了), 把 callback 合併進同個 context︰ // async 函式呼叫時會回傳 Promise async function getValues() { var x, y; x = await getValue(); // await 會使 context 暫停,等待右方的 Promise 回 // 傳結果 y = await getValue(); console.log(x, y); // 函式結束時,Promise 被 resolve } getValues(); 但是「同步函數接異步函數返回值」仍然是不可能的, getValues 本身是異步函數,回傳 Promise。 -- (* ̄▽ ̄)/‧★*"`'*-.,_,.-*'`"*-.,_☆,.-*` http://i.imgur.com/oAd97.png --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.166.131.180
※ 文章網址: https://webptt.com/m.aspx?n=bbs/Ajax/M.1489324789.A.266.html
1F:推 Sunal: 阿~~~頭好痛 03/12 21:46
2F:→ dannypsnl: 就是非同步為了確保程式正確按順序執行就要一個callbac 03/12 23:42
3F:→ dannypsnl: k包著一個,非常的有事(咦 03/12 23:42
4F:→ dannypsnl: 重點是很難一眼看懂,Promise只是把這件事變成一個鏈結 03/12 23:42
5F:→ dannypsnl: ,但本質還是上面那樣 03/12 23:42
6F:推 ZAbird: 完全看懂了!!而且也會實際上的操作跟想法 03/13 01:33
7F:→ ZAbird: 真的非常非常感謝你用心回我 幫我建立觀念 03/13 01:33
8F:→ ZAbird: 其他語言寫習慣了 用js真的是又崩潰又有趣XD 03/13 01:33
9F:→ ZAbird: async/await 看起來真的精簡很多, 但支援度目前還不高? 03/13 01:35
10F:推 cliffk321: 推用心 03/13 02:32
11F:→ eight0: 對於支援度方面,可以參考 Babel/Buble 等的轉譯器 03/13 07:32
12F:→ eight0: https://babeljs.io/ https://buble.surge.sh/guide/ 03/13 07:32
13F:→ ssccg: 同步接異步不可能是因為js的event loop架構,在其他語言一 03/13 09:49
14F:→ ssccg: 樣有這套async機制,但是真的要接回sync就把原thread block 03/13 09:51
15F:→ ssccg: 即可,但在js中原則上不能也不應該這樣做 03/13 09:51
16F:推 wotupset: 用心推 03/15 19:34







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:iOS站內搜尋

TOP