Promise
JavaScript 是属於同步的程序语言,因此一次仅能做一件事情,但遇到非同步的事件时,就会将非同步的事件移动到程序码的最後方,等到所有的原始码运行完以後才会执行非同步的事件。
以下列的程序码来说,在 console 中依序的会出现的顺序为:
开始
结束
非同步事件 <- 最後执行
console.log('开始');
setTimeout(() => {
console.log('非同步事件');
}, 0);
console.log('结束');
虽然在上段的原始码中,setTimeout
所定义的时间为 0,但因为是属於非同步事件,因此还是会在其他原始码运行完以後才执行。
我们再axios
文件中找一段实际范例参考,先定义一个data物件
,中间段落使用 axios
尝试取得远端资料,後面的紧接的 console.log(data),实际测试看看console的结果是什麽?
你应该会觉得concole顺序依序为:
"开始执行"
'/user?ID=12345
"测试有没有接收到资料"
let data = {}
console.log('开始执行');
const api = '/user?ID=12345'
axios.get(api).then(response => {
data = response;
console.log('测试有没有接收到资料');
});
console.log(data);
其实正确的 console 中依序的会出现的顺序是:
"开始执行"
[object Object] { ... }
"测试有没有接收到资料"
你应该会想说为什麽console.log(data)会没有接收到资料呢?
因为上述的非同步行为,导致api还尚未接收到,因此才会出现[object]
实战演练Promise,以Vue为范例
一、数字题型:
const app = new Vue({
el: '#app',
created() {
this.promise(100)
.then(success => {
console.log(success);
return this.promise(1000);
})
.then(success => {
console.log(success);
return this.promise(0); // 这个阶段会进入 catch
})
.then(success => { // 由於上一个阶段结果是 reject,所以此段不执行
console.log(success);
return this.promise('Hello');
})
.catch(error => {
console.log(error);
})
},
methods: {
promise (num) {
return new Promise((resolve, reject) => {
num ? resolve('成功') : reject('失败');
});
}
},
})
因此console出来的结果为:
成功
成功
失败
二、JSON Data一般题型:
将题型一的值更改为JSON,分别为apiA
以及apiB
可将此段程序码复制贴到开发者工具
看有没有什麽不同的地方~
const app = new Vue({
el: '#app',
created () {
const apiA = 'https://data.taipei/api/v1/dataset/80ab7634-dabd-4012-be8c-fb7da0101e9b?scope=resourceAquire'
const apiB = 'https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire'
this.demo(apiA).then(res => {
console.log(res)
return this.demo(apiB)
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
},
methods: {
demo (api) {
return new Promise((resolve, reject) => {
axios.get(api).then((res) => {
const data = res.data.result.results
res.status === 200 ? resolve(data) : reject('error api')
})
})
}
}
})
三、进阶题型:
使用indexOf
去寻找哪个api中有符合80ab7634
的字串,有的话则会执行setTimeout
延迟5秒!
然而,在这个范例中indexOf
寻找到apiA
有符合,但是js是由上到下去执行的,因此js会等待apiA
回传回来後,接着马上跟着回传apiB
,因此apiA与apiB
都将延迟5秒回传
const app = new Vue({
el: '#app',
created() {
const apiA = 'https://data.taipei/api/v1/dataset/80ab7634-dabd-4012-be8c-fb7da0101e9b?scope=resourceAquire'
const apiB = 'https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire'
this.demo(apiA).then(res => {
console.log(res);
return this.demo(apiB)
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
},
methods: {
demo(api) {
return new Promise((resolve, reject) => {
axios.get(api).then((res) => {
if (res.status === 200) {
if (api.indexOf('80ab7634') > -1) {
setTimeout(() => {
resolve(res.data)
}, 5000)
} else {
resolve(res.data)
}
} else {
reject('error api')
}
})
})
},
},
})
假如我们将indexOf的值变更为36847f3f
,猜猜看会出现什麽有趣的事呢?
这时会发现,js先回传apiA
,经过了5秒後才会回传apiB
因为js未搜寻到apiA有36847f3f
的值,因此不会去执行setTimeOut
const app = new Vue({
el: '#app',
created() {
const apiA = 'https://data.taipei/api/v1/dataset/80ab7634-dabd-4012-be8c-fb7da0101e9b?scope=resourceAquire'
const apiB = 'https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire'
this.demo(apiA).then(res => {
console.log(res);
return this.demo(apiB)
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
},
methods: {
demo(api) {
return new Promise((resolve, reject) => {
axios.get(api).then((res) => {
if (res.status === 200) {
if (api.indexOf('36847f3f') > -1) {
setTimeout(() => {
resolve(res.data)
}, 5000)
} else {
resolve(res.data)
}
} else {
reject('error api')
}
})
})
},
},
})
希望藉由上述三个不同的简单实例,能让大家更了解Promise的运作模式
<<: EasyFlow 传送表单回Tiptop错误讯息显示:找不到指定的服务主机
今天天气真好,最适合来学习新事物了!!在创建一个网页时,有可能会遇到需要把使用者输入的文字转成大小写...
前情提要 艾草:「不知不觉也累积了不少魔力总量了,我们今天透过魔法阵列来找出你适合的属性值吧!」 「...
前情提要 一般我们要在 App 中显示 PDF 档案,可能会透过 WKWebView 来进行实作 最...
打造自己的 Hook 自 React 16.8 以後, 使用者就可以在 React 中 创建自定义的...
https://wolkesau.medium.com/资料结构和演算法-c3a453c9c64c ...