@gdjiami/jslib
Version:
Jiami FrontEnd helpers and Services
224 lines (223 loc) • 7.68 kB
JavaScript
/**
* promise、异步操作相关的工具函数。
*/
import * as tslib_1 from "tslib";
/**
* 延迟指定毫秒
*/
export function delay(ms) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, new Promise(function (res) { return setTimeout(res, ms); })];
});
});
}
/**
* 增加超时机制的promise
*/
export function promiseWithTimeout(prom, timeout) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve, reject) {
var resolved;
var resolver = function (val) {
if (resolved) {
return;
}
resolved = true;
resolve(val);
};
var rejector = function (reason) {
if (resolved) {
return;
}
resolved = true;
reject(reason);
};
setTimeout(function () { return rejector(new Error('timeout')); }, timeout);
prom(resolver, rejector);
})];
});
});
}
/**
* 可重试的promise, 出现异常时进行重试
* @param prom
* @param time 重试的次数
* @param duration 重试的间隔
*/
export function retryablePromise(prom, time, duration) {
if (time === void 0) { time = 1; }
if (duration === void 0) { duration = 0; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var i, rt, err_1;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
i = 0;
_a.label = 1;
case 1:
if (!(i < time)) return [3 /*break*/, 8];
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 7]);
return [4 /*yield*/, prom()];
case 3:
rt = _a.sent();
return [2 /*return*/, rt];
case 4:
err_1 = _a.sent();
if (!(i < time)) return [3 /*break*/, 6];
return [4 /*yield*/, delay(duration)];
case 5:
_a.sent();
return [3 /*break*/, 7];
case 6: throw err_1;
case 7:
i++;
return [3 /*break*/, 1];
case 8: return [2 /*return*/, undefined];
}
});
});
}
/**
* 抽取出promise的Resolve和Reject函数, 可以在外部进行使用
*
* @example
* ```js
* const { promise, reject, resolve } = extraPromise()
* ```
*/
export function extraPromise() {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var resolve, reject, promise;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
promise = new Promise(function (res, rej) {
resolve = res;
reject = rej;
});
return [4 /*yield*/, delay(0)];
case 1:
_a.sent();
return [2 /*return*/, {
promise: promise,
reject: reject,
resolve: resolve,
}];
}
});
});
}
/**
* 按照 push 顺序执行并发的任务
* 防止并发多个任务只执行一个任务后其他任务被销毁
*
* @typeParam R 自定义返回值类型
*
* @returns push 将异步操作加入任务队列,run 按顺序执行任务队列里的所有异步操作
*
* @example
*
* ```js
*
* const tasks = concurrentTask<MessageData[] | undefined>()
*
* for (let i = 0; i < messages.length; i++) {
* tasks.push(() => {}) // tasks.push(Promise<any>)
* }
* const res = await tasks.run()
*
* ```
*/
export function concurrentTask() {
var _this = this;
var i = 0;
var tasks = [];
var run = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, Promise.all(tasks).then(function (arr) {
return arr.sort(function (a, b) { return a.index - b.index; }).map(function (i) { return i.res; });
})];
});
}); };
var push = function (task) {
var order = i++;
tasks.push(new Promise(function (resolve, reject) {
task()
.then(function (res) {
resolve({ index: order, res: res });
})
.catch(reject);
}));
};
return {
push: push,
run: run,
};
}
var pendingTask = {};
/**
* 执行异步任务, 它会处理重复发起的任务
* @param id 任务唯一索引
* @param task 异步执行方法
*
* @example
*
* ```js
* const res = await executeAsyncTask<User>('get-user', async () => Promise<User>) // 如多次发起请求,只会请求一次
* ```
*/
export function executeAsyncTask(id, task) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var e_1, _a, res, err, err_2, _b, _c, t;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0:
if (id in pendingTask) {
return [2 /*return*/, new Promise(function (resolve, reject) {
pendingTask[id].push({ resolve: resolve, reject: reject });
})];
}
_d.label = 1;
case 1:
_d.trys.push([1, 3, , 4]);
pendingTask[id] = [];
return [4 /*yield*/, task()];
case 2:
res = _d.sent();
return [3 /*break*/, 4];
case 3:
err_2 = _d.sent();
err_2 = err_2;
return [3 /*break*/, 4];
case 4:
try {
for (_b = tslib_1.__values(pendingTask[id]), _c = _b.next(); !_c.done; _c = _b.next()) {
t = _c.value;
if (err != null) {
t.reject(err);
}
else {
t.resolve(res);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
delete pendingTask[id];
if (err != null) {
throw err;
}
return [2 /*return*/, res];
}
});
});
}