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/cn.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灯, 水草

请输入看板名称,例如:WOW站内搜寻

TOP