1 | # promise-abortable
|
2 |
|
3 | Promise lib for abortable.
|
4 |
|
5 |
|
6 |
|
7 | ## Install
|
8 |
|
9 | ### NPM
|
10 |
|
11 | ```bash
|
12 | $ npm install promise-abortable
|
13 | ```
|
14 |
|
15 | ### Browser (with polyfill)
|
16 | ```html
|
17 | <script src="https://unpkg.com/promise-abortable/dist/index.min.js"></script>
|
18 | ```
|
19 |
|
20 |
|
21 |
|
22 | ## Usage
|
23 |
|
24 | ```javascript
|
25 | const promise = new AbortablePromise((resolve, reject, signal) => {
|
26 | signal.onabort = reason => {}; // reason from abort(reason)
|
27 | });
|
28 |
|
29 | promise.abort(reason); // execute signal.onabort(reason)
|
30 | ```
|
31 |
|
32 |
|
33 |
|
34 | ## Examples
|
35 |
|
36 | ### Abort Promise
|
37 |
|
38 | ```javascript
|
39 | const promise1 = new AbortablePromise((resolve, reject, signal) => {
|
40 | setTimeout(resolve, 1000, "resolve");
|
41 | signal.onabort = reject;
|
42 | });
|
43 |
|
44 | const promise2 = promise1.then(value => {
|
45 | console.log(value); // no execute
|
46 | }).catch(reason => {
|
47 | console.log(reason); // output "abort promise"
|
48 | });
|
49 |
|
50 | promise1.abort("abort promise");
|
51 | // or
|
52 | promise2.abort("abort promise");
|
53 | ```
|
54 |
|
55 |
|
56 | ### Abort AJAX
|
57 |
|
58 | ```javascript
|
59 | const promise = new AbortablePromise((resolve, reject, signal) => {
|
60 | const url = `/`;
|
61 | const xhr = $.ajax({ url, success: resolve, error: reject });
|
62 | signal.onabort = xhr.abort.bind(xhr);
|
63 | });
|
64 |
|
65 | promise.then(data => {
|
66 | console.log(data); // no execute
|
67 | }).catch(xhr => {
|
68 | console.log(xhr); // output `{ ... statusText: "abort ajax" }`
|
69 | });
|
70 |
|
71 | promise.abort("abort ajax");
|
72 | ```
|
73 |
|
74 |
|
75 | ### Abort axios
|
76 |
|
77 | ```javascript
|
78 | const promise = new AbortablePromise((resolve, reject, signal) => {
|
79 | const url = `/`;
|
80 | const source = axios.CancelToken.source();
|
81 | axios({ url, cancelToken: source.token }).then(resolve, reject);
|
82 | signal.onabort = source.cancel.bind(source);
|
83 | });
|
84 |
|
85 | promise.then(response => {
|
86 | console.log(response); // no execute
|
87 | }).catch(error => {
|
88 | console.log(error); // output `{ message: "abort axios" }`
|
89 | });
|
90 |
|
91 | promise.abort("abort axios");
|
92 | ```
|
93 |
|
94 |
|
95 | ### Abort fetch
|
96 |
|
97 | ```javascript
|
98 | const promise = new AbortablePromise((resolve, reject, signal) => {
|
99 | const url = `/`;
|
100 | const controller = new AbortController();
|
101 | fetch(url, { signal: controller.signal }).then(resolve, reject);
|
102 | signal.onabort = controller.abort.bind(controller);
|
103 | });
|
104 |
|
105 | promise.then(response => {
|
106 | console.log(response); // no execute
|
107 | }).catch(error => {
|
108 | console.log(error); // output `DOMException`
|
109 | });
|
110 |
|
111 | promise.abort("abort fetch");
|
112 | ```
|
113 |
|
114 |
|
115 |
|
116 | ## More
|
117 |
|
118 | ```javascript
|
119 | /**
|
120 | * Timeout Promise: resolved after delay, abortable
|
121 | *
|
122 | * @param {*} value
|
123 | * @param {Number} delay
|
124 | */
|
125 | function AbortableDelay (value, delay = 0) {
|
126 | return new AbortablePromise((resolve, reject, signal) => {
|
127 | setTimeout(resolve, delay, value);
|
128 | signal.onabort = reject;
|
129 | });
|
130 | }
|
131 | ```
|
132 |
|
133 |
|
134 | ### Nesting abort
|
135 |
|
136 | ```javascript
|
137 | const promise1 = AbortableDelay("resolve at 1s", 1000);
|
138 | const promise2 = AbortableDelay("resolve at 2s", 2000);
|
139 | const promise3 = AbortableDelay("resolve at 3s", 3000);
|
140 | const promise4 = AbortableDelay("resolve at 4s", 4000);
|
141 |
|
142 | promise1.then(value => {
|
143 | console.log("promise1:", value); // output "promise1: resolve at 1s"
|
144 | return promise2;
|
145 | }).catch(reason => {
|
146 | console.log("promise2:", reason); // output "promise2: abort at 1.5s"
|
147 | return promise3;
|
148 | }).then(value => {
|
149 | console.log("promise3:", value); // output "promise3: resolve at 3s"
|
150 | return promise4;
|
151 | }).catch(reason => {
|
152 | console.log("promise4:", reason); // output "promise4: abort at 3.5s"
|
153 | });
|
154 |
|
155 | setTimeout(() => {
|
156 | promise1.abort("abort at 1.5s");
|
157 | }, 1500);
|
158 |
|
159 | setTimeout(() => {
|
160 | promise1.abort("abort at 3.5s");
|
161 | }, 3500);
|
162 | ```
|
163 |
|
164 |
|
165 | ### Promise after abort
|
166 |
|
167 | ```javascript
|
168 | const promise = AbortableDelay("resolve", 1000);
|
169 |
|
170 | const promise1 = promise.catch(reason => {
|
171 | console.log("promise1:", reason); // output "promise1: abort"
|
172 | return "catch abort 1";
|
173 | });
|
174 |
|
175 | const promise2 = promise.catch(reason => {
|
176 | console.log("promise2:", reason); // output "promise2: abort"
|
177 | return "catch abort 2";
|
178 | });
|
179 |
|
180 | promise1.abort("abort").then(value => {
|
181 | console.log(value); // output "catch abort 1"
|
182 | });
|
183 | ```
|
184 |
|
185 |
|
186 | ### Promise.all abort
|
187 |
|
188 | ```javascript
|
189 | const promise1 = AbortableDelay("resolve at 1s", 1000);
|
190 | const promise2 = AbortableDelay("resolve at 2s", 2000);
|
191 | const promiseAll = AbortablePromise.all([promise1, promise2]);
|
192 |
|
193 | promise1.then(value => {
|
194 | console.log("promise1:", value); // output "promise1: resolve at 1s"
|
195 | }).catch(reason => {
|
196 | console.log("promise1:", reason); // no execute
|
197 | });
|
198 |
|
199 | promise2.then(value => {
|
200 | console.log("promise2:", value); // no execute
|
201 | }).catch(reason => {
|
202 | console.log("promise2:", reason); // output "promise2: abort at 1.5s"
|
203 | });
|
204 |
|
205 | promiseAll.then(value => {
|
206 | console.log("promiseAll:", value); // no execute
|
207 | }).catch(reason => {
|
208 | console.log("promiseAll:", reason); // output "promiseAll: abort at 1.5s"
|
209 | });
|
210 |
|
211 | setTimeout(() => {
|
212 | promiseAll.abort("abort at 1.5s");
|
213 | }, 1500);
|
214 | ```
|
215 |
|
216 |
|
217 | ### Promise.race abort
|
218 |
|
219 | ```javascript
|
220 | const promise1 = AbortableDelay("resolve at 1s", 1000);
|
221 | const promise2 = AbortableDelay("resolve at 2s", 2000);
|
222 | const promiseRace = AbortablePromise.race([promise1, promise2]);
|
223 |
|
224 | promise1.then(value => {
|
225 | console.log("promise1:", value); // output "promise1: resolve at 1s"
|
226 | }).catch(reason => {
|
227 | console.log("promise1:", reason); // no execute
|
228 | });
|
229 |
|
230 | promise2.then(value => {
|
231 | console.log("promise2:", value); // no execute
|
232 | }).catch(reason => {
|
233 | console.log("promise2:", reason); // output "promise2: abort at 1.5s"
|
234 | });
|
235 |
|
236 | promiseRace.then(value => {
|
237 | console.log("promiseRace:", value); // output "promiseRace: resolve at 1s"
|
238 | }).catch(reason => {
|
239 | console.log("promiseRace:", reason); // no execute
|
240 | });
|
241 |
|
242 | setTimeout(() => {
|
243 | promiseRace.abort("abort at 1.5s");
|
244 | }, 1500);
|
245 | ```
|