Javascript-Cheatsheet
文章目录

Loop/循环

Object

Object.keys

1
2
3
4
5
6
7
8
const fruits = {
apple: 28,
orange: 17,
pear: 54,
}

const keys = Object.keys(fruits)
console.log(keys) // [apple, orange, pear]

Object.values

1
2
3
4
5
6
7
8
const fruits = {
apple: 28,
orange: 17,
pear: 54,
}

const values = Object.values(fruits)
console.log(values) // [28, 17, 54]

Object.entries

1
2
3
4
5
6
7
8
9
10
11
12
13
const fruits = {
apple: 28,
orange: 17,
pear: 54,
}

const entries = Object.entries(fruits)
console.log(entries)
// [
// [apple, 28],
// [orange, 17],
// [pear, 54]
// ]

Types/类型

Numeric Test/是否为数字

2020

1
2
3
function isNumeric(num){
return !isNaN(num)
}

Modulization/模块化

Modules Import/Export

Export 基本语法:

  1. 可以暴露一个已经声明的变量, 类或者函数
  2. 可以暴露一个立刻声明的变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
var name = "xxx";
export {
name
}
/*
// 效果相同
export var name="xxx";
*/
...

import {
name
} from "/xxx"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var name1 = "xxx";
var name2 = "yyy";
export {
name1,
name2
}

/*
// 效果相同
export name1;
export name2;
*/

...

import {
name1 as x1,
names as x2
} from "/xxx"
1
2
3
4
5
6
7
8
9
10
const getdata = () => {
...
}
export default getdata;
// 一个文件中default 只能使用一次。

...

import getdata from './XXX'
// 特别注意这个地方没有花括号

Export anonymous function

Default is required due to anonymous export

1
2
3
4
5
export default () => console.log("say hello");

...

import str as XXX from 'demo1' //导入的时候没有花括号

Module Pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var myModule = (function() {
'use strict';

var _privateProperty = 'Hello World';
var publicProperty = 'I am a public property';

function _privateMethod() {
console.log(_privateProperty);
}

function publicMethod() {
_privateMethod();
}

return {
publicMethod: publicMethod,
publicProperty: publicProperty
};
}());

/* private 和 public 的区别就在于是否返回了出来 */

console.log(myModule.publicProperty);
// outputs 'I am a public property'
console.log(myModule._privateProperty);
// is undefined protected by the module closure

myModule._privateMethod();
// is TypeError protected by the module closure
myModule.publicMethod();
// outputs 'Hello World'

几种变体

传递参数
1
2
3
4
5
var myModule = (function(args) {

/* 将参数传递进去 */

}(……args……));

Named Function & Anonymous Function

1
2
3
4
5
6
7
8
9
10
11
12
13
var myModule = (function() {

var privateField = 12345;

function _privateMethod() {
/* 可以访问到 privateField */
}

var _privateMethod = function() {
/* 无法访问到 privateField */
}

}());

Array/数组相关

Reduce

1
2
3
4
5
6
7
8
9
10
11
var rv = [];
[1, 2, 3, 4, 5].reduce((a, c) => {
let str = a + ((c === 1) ? '' : '/') + c;
rv.push(str);
return str;
}, []);atte

/*
Input: [1,2,3,4,5]
Output: ["1", "1/2", "1/2/3", "1/2/3/4", "1/2/3/4/5"]
*/

Example

1
2
3
4
x = [1, 2, 3, 4];
x.reduce((accumulator, currentValue) => (accumulator + currentValue), 0);
// 设置了 0 为初始值, 如果没有初始值那么会将第一个元素当成 acc 放进去, 可能会忽略第一个参数
// output 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[1, 2, 3, 4, 5, 6, 7, 8, 9].reduce((acc, cv) => (acc + cv))
// 45, 因为一开始 1 就被作为 acc 了

[1, 2, 3, 4, 5, 6, 7, 8, 9].reduce((acc, cv) => (acc + cv), 10)
// 55

[{
a: 1,
b: 2
}, {
a: 2,
b: 3
}].reduce((acc, cv) => acc + cv.a, 0)
// 3, 全部 a 的总和是 3

[{
a: 1,
b: 2
}, {
a: 2,
b: 3
}].reduce((acc, cv) => acc + cv.b, 0)
// 5

.slice()

获取数组的最后一个 elem

1
2
var myArray = [1, 2, 3, 4, 5, 6];
console.log(myArray.slice(-1)[0])

移除特定 elem

1
2
3
4
5
6
7
8
9
10
// splice(startFromWhichIndex, deleteLength0)
// array self will be updated

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
var removed = arr.splice(2, 2);

/*
removed === [3, 4]
arr === [1, 2, 5, 6, 7, 8, 9, 0]
*/

快速生成数组

1
2
3
4
5
6
7
8
9
[...Array(10).keys()];
// 生成 0-9

[...Array(10).keys()].map(e => e + (new Date).getFullYear())
// 如果需要其他数组就 map 一下
// 这个例子生成了当前年份前后5年的数字

Array(10).fill(1)
// 生成一堆 1

Array Flaten/Duplicate Removal/Sort/数组去重

一位数组去重

ES6

1
2
3
4
[……new Set([1, 1, 2, 2, 3, 3])]
// 首先是 Set 去重, Set 的结果是一个 Obj
// 注意 Set 使用时需要关键字 new
// 然后使用 spread operator 展开

多维数组去重

数组平化, 去重, 排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var arr = [
[1, 2, 2],
[3, 4, 5, 5],
[6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10
];

Array.from(new Set(arr.flat(Infinity))).sort((a, b) => {
return a - b
})

// 或者使用 spread operator

[……new Set(arr.flat(Infinity))].sort((a, b) => {
return a - b
})

// arr.flat(Infinity) 无限层扁平化, 多维数组全部变为一维数组
// Array.from(new Set(arr)) 传递数组给 Set
// 最后排序

Object 数组去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const seen = new Set();
const arr = [
{ id: 1, name: "test1" },
{ id: 2, name: "test2" },
{ id: 2, name: "test3" },
{ id: 3, name: "test4" },
{ id: 4, name: "test5" },
{ id: 5, name: "test6" },
{ id: 5, name: "test7" },
{ id: 6, name: "test8" }
];

const filteredArr = arr.filter(el => {
const duplicate = seen.has(el.id);
seen.add(el.id);
return !duplicate;
});

ES5 备选方法

ES5 使用对象属性单一性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function distinct(a, b) {
let arr = a.concat(b) // 先将两个数组拼起来
let result = []
let obj = {}

for (let i of arr) {
if (!obj[i]) { // 如果数组里面没有这个元素
result.push(i)
obj[i] = 1
}
}

return result
}

Operator/操作符运算

位运算

请注意 位运算适用于 32 位整数, 所以精度可能会丢失

  • 用 “|” 取整
1
2
let num = 1.5
num = num | 0 // 1
  • 用 “>>” 取半
1
2
let num = 4
num = num >> 1 // 2
  • 用 “>>” 加倍
1
2
let num=2;
num=num<<1; / / 4
  • 用 “^” 两值交换
1
2
3
4
5
6
7
let a = 1
let b = 2

a ^= b
b ^= a
a ^= b
// a===2,b===1
  • 用 “&” 判断奇数
1
2
3
4
let n = 3
let m = 4
n & (1 === 1) // true 奇数
m & (1 === 1) // false 偶数
  • 用 “~” 判断项是否存在
1
2
3
let firstname = 'Ma'
let fullname = 'Jack Ma'
let isExist = !!~fullname.indexOf(firstname) // true

String/字符串相关

match() - 正则表达式匹配

Get occurrences count of substring in a string

1
2
3
4
5
6
7
8
9
10
11
//
// Example:
// '123123'.match(new RegExp("1", "g"))
//
// Output:
// ["1", "1"]
//
// If no substring found will return null !!!
//
let singleCountObj = s.match(new RegExp("a", "g"));
let singleCount = (singleCountObj !== null) ? singleCountObj.length : 0;

replace() - 正则表达式替换

正则表达式替换

1
2
3
'213-123-321-321'.replace(/-/g, '')
// 第一个参数没有引号!!!
// 213123321321

split() - 条件切割字符串

1
2
3
4
5
6
7
8
// 正常使用的况下当然是直接照特定的字符分割。
'123-456-789-102'.split('-')
//  ["123", "456", "789", "102"]


// 也可以限定值取前面几个
'123-456-789-102'.split('-', 2)
//  ["123", "456"]

Asynchronous Request/异步请求

fetch()

1
2
3
4
5
6
7
8
9
fetch(url, {
method: 'POST', // or 'PUT'
body: JSON.stringify(data), // data can be `string` or {object}!
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));

如果没有 content-type 那么 body 会被当成字符串传递, 服务端解析会麻烦一些

fetch() 和 async/await

需要注意的是, 转换成 json 的时候也需要加一个 await, 不然会返回空

1
2
3
4
5
6
7
8
9
10
11
12

const handler = async (req, res) => {
try {
const request = await fetch("xxx.com/api");

/* 下面这里也一定要加上一个 await */
res.send(await request.json());

} catch (error) {
console.log(error);
}
};

ajax with serialized form

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$.ajax({
url: 'xxx.cfm?t=10EFCE11946ABB54D46EB44607097E60EAE5384E87E8&cfcid=3e481ba9f2a444c9987f068177150742',
method: 'post',
data: $('form').serialize()
})
.done(function(res) {
// TODO
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});

Error Handling

Try-Catch

1
2
3
4
5
6
7
try {
throw "myException"; // generates an exception
}
catch (e) {
// statements to handle any exceptions
logMyErrors(e); // pass exception object to error handler
}

ESLint:

Restrict what can be thrown as an exception (no-throw-literal)

其实就是不让直接扔出字符串的错误, 改为扔出一个 Object 就行

1
2
3
4
5
6
throw new Error();

throw new Error("error");

var e = new Error("error");
throw e;

其他框架

Lodash

Lodash Template with condition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var itemRowTemplate = _.template([
'<tr>',
'<td class="btn-link pointer itemViewLink" data-spgid="<%= spgid %>">',
'<%= itemnumber %><br><%= itemname %>',
'<% if (hasMark == true) { %>',
'<i class="fa fa-flag text-danger pull-right"></i>',
'<% } %>',
'</td>',
'</tr>'
].join(''));

/* some other issues */

itemRowTemplate({
itemnumber: row.customid,
itemname: row.groupname,
spgid: row.surveypartnergroupid,
itemconcentrationexceeded: row.itemconcentrationexceeded,
itemstatus: (row.approvalstatus.length > 0) ? row.approvalstatus : 'No Response',
})

Select2

Javascript: Select2 多选的实现

实际上很简单

HTML 部分加一个 multiple="true"
然后 select2.init 的时候加一个参数 isMultiple: isMultiple

Datatable

Datatable 输出 Excel 时添加额外行

Add extra rows for datatable-exported-excel

方法 1: datatable.init 之前用 JS 添加额外行, 此方法无法添加到 header 之前
方法 2: 对 Excel 进行操作

主要说方法 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
$('table#datatable').dataTable({
buttons: [{
extend: 'excelHtml5',
customize: function(xlsx) {
var sheet = xlsx.xl.worksheets['sheet1.xml'];
var downrows = 7;
var clRow = $('row', sheet);

// add styles for the column header, and row[0] will be move down later
$(clRow[0]).find('c').attr('s', 31);

//update Row
clRow.each(function() {
var attr = $(this).attr('r');
var ind = parseInt(attr);
ind = ind + downrows;
$(this).attr("r", ind);
});

// Update row > c
$('row c ', sheet).each(function() {
var attr = $(this).attr('r');
var pre = attr.substring(0, 1);
var ind = parseInt(attr.substring(1, attr.length));
ind = ind + downrows;
$(this).attr("r", pre + ind);
});

function Addrow(index, data) {
msg = '<row r="' + index + '">'
for (i = 0; i < data.length; i++) {
var key = data[i].k;
var value = data[i].v;
msg += '<c t="inlineStr" r="' + key + index + '">';
msg += '<is>';
msg += '<t>' + value + '</t>';
msg += '</is>';
msg += '</c>';
}
msg += '</row>';
return msg;
}

//add data to extra rows
var countryStateList = $('select[name=f_stateidlist] option:selected').map(function(index, elem) {
return $(elem).attr('title').trim().replace('>>', '');
}).get().join(",");
var agencyValue = $('select[name=f_agency] option:selected').val();
var reportGroupList = $('select[name=f_reportgroup] option:selected').map(function(index, elem) {
return $(elem).attr('title').trim();
}).get().join(",");
var repealValue = $('select[name=f_repealed] option:selected').val();
var actTypeValue = $('select[name=f_actiontype] option:selected').val();
var updateStatusValue = $('select[name=f_rulestatus] option:selected').val();
countryStateList = (countryStateList != "") ? countryStateList : 'All';
agencyValue = (agencyValue != "") ? agencyValue : 'All';
reportGroupList = (reportGroupList != "") ? reportGroupList : 'All';
repealValue = (repealValue != "") ? repealValue : 'All';
actTypeValue = (actTypeValue != "") ? actTypeValue : 'All';
updateStatusValue = (updateStatusValue != "") ? updateStatusValue : 'All';
var r1 = Addrow(1, [{
k: 'A',
v: 'Report Filter Criteria:'
},
{
k: 'B',
v: ''
}
]);
var r2 = Addrow(2, [{
k: 'A',
v: 'Country/State:'
},
{
k: 'B',
v: countryStateList
}
]);
var r3 = Addrow(3, [{
k: 'A',
v: 'Agency:'
},
{
k: 'B',
v: agencyValue
}
]);
var r4 = Addrow(4, [{
k: 'A',
v: 'Report Group:'
},
{
k: 'B',
v: reportGroupList
}
]);
var r5 = Addrow(5, [{
k: 'A',
v: 'Repealed:'
},
{
k: 'B',
v: repealValue
}
]);
var r6 = Addrow(6, [{
k: 'A',
v: 'Action Type:'
},
{
k: 'B',
v: actTypeValue
}
]);
var r7 = Addrow(7, [{
k: 'A',
v: 'Update Status:'
},
{
k: 'B',
v: updateStatusValue
}
]);
var nodeHTML = r1 + r2 + r3 + r4 + r5 + r6 + r7 + sheet.childNodes[0].childNodes[1].innerHTML

sheet.childNodes[0].childNodes[1].innerHTML = noteHTML ;
}
}]
});

Datatable 自定义 Excel/Print 输出 Column

Datatable 限定特定行 允许/不允许 排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$('#results').html(res); // res = html pure table with good format
$('#results table').DataTable({
"buttons": [{
extend: 'print',
text: '<i class="fa fa-print" title="Print"></i>',
className: "mb-2",
exportOptions: {
columns: [0, 1, 2, 3, 4]
}
}, {
extend: 'excelHtml5',
text: '<i class="fa fa-file-excel-o" title="Excel Download"></i>',
className: "mb-2",
exportOptions: {
columns: [0, 1, 2, 3, 4]
}
}]
});

各种按钮的 Action 列表:https://datatables.net/reference/button/


Datatable 额外筛选条件 & 绑定额外 filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$.fn.dataTable.ext.search.push(
/* 这里 push 了一个方法, 每次 draw 的时候就会调用这个方法 */
function(settings, data, dataIndex) {
var status = $('#approvalStatus').val();

// 这里判断 status 和 data[1], 返回 true 的话就显示, 否则不显示
if (status == "") return true;
else if (data[1] == status) return true;
else return false;
}
);

/* 给特定的 filter 绑定事件, 选择之后进行筛选 */
$('#approvalStatus').change(function(event) {
/* temp save the filter to global var */
if ($(this).val() !== '') currStatus = $(this).val();
dataTable.draw(false);
});

Datatable 获取当前页数 & 获取总页数 & 跳转到特定页

1
2
3
4
5
6
7
var dataTable = $itemDashboardCard.find('table').DataTable({
……});

dataTable.page.info().page; // 当前页数 index, 这个是 index 从 0 开始
dataTable.page.info().pages; // 总页数计数

dataTable.page(currPageIndex).draw(false); // 跳转到 index = currPageIndex 的那一页

Datatable 限定特定行 允许/不允许 排序

tags: datatable, excel, print, 限制, 隐藏

1
2
3
4
"columnDefs": [{
orderable: false,
targets: [5]
}],

这样第 6 列就不会输出了, 注意从 0 开始

Datatable 监听每一次刷新表格

分页, 筛选都会调用到

1
2
3
"drawCallback": function(settings) {
debugger
}

Object

Object.assign()

实际上就是将几个参数合并到第一个参数而已啦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var o1 = {
a: 1,
b: 1,
c: 1
};
var o2 = {
b: 2,
c: 2
};
var o3 = {
c: 3
};

var obj = Object.assign({}, o1, o2, o3);
//首先将第二个和第一个得到 A, 然后将第三个合并到之前的结果 A
console.log(obj); // { a: 1, b: 2, c: 3 }

需要注意的一点: 第一个参数在合并之后会改变, 其他参数不会

1
2
3
4
5
6
7
8
9
10
11
12
13
var o1 = {
a: 1
};
var o2 = {
b: 2
};
var o3 = {
c: 3
};

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

DOM Event

关于 Element.onclick

1
2
3
4
newElem.onclick = function() {
document.getElementById('' + newRowID).className = "tbl_highlightRow";
PCC_Notes_deleteNote(newRowID, noteID);
}

注意这里不需要写 new function

Misc

Deep Clone

1
2
3
4
5
6
7
8
9
10
11
const deepClone = obj => {
let clone = Object.assign({}, obj);
Object.keys(clone).forEach(
key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
);
return Array.isArray(obj) && obj.length ?
(clone.length = obj.length) && Array.from(clone) :
Array.isArray(obj) ?
Array.from(obj) :
clone;
};

动态提交 Form

1
2
3
4
5
6
7
8
9
10
11
var form = document.createElement("form");
form.id = "form";

var input = document.createElement("input");
input.name = "index";
input.value = $(this).data('metaresultid');
form.appendChild(input);

form.method = "POST";
form.action = "tib.cfm?ajaxModal";
form.submit();

进制转换

左边是修改前的进制, 右边是修改后的

1
2
3
4
5
6
7
8
9
10
11
12
to = parseInt(num).toString(2);
to = parseInt(num).toString(8);
to = parseInt(num).toString(16);
to = parseInt(num, 2);
to = parseInt(num, 8);
to = parseInt(num, 16);
to = parseInt(num, 2).toString(8);
to = parseInt(num, 8).toString(2);
to = parseInt(num, 2).toString(16);
to = parseInt(num, 16).toString(2);
to = parseInt(num, 8).toString(16);
to = parseInt(num, 16).toString(8);

定义
eval() 函数可计算某个字符串, 并执行其中的的 JavaScript 代码.


eval()

实例

1
2
3
4
eval("x=10;y=20;document.write(x*y)")
document.write(eval("2+2"))
var x=10
document.write(eval(x+17))

实例 2

主要通过配合 Object 使用, 可以访问不确定的属性

1
2
3
4
person=new Object();
person.age=56;
var attrname="age";
eval("alert(person."+attrname+");");

键盘事件监听

1
2
3
4
5
6
7
8
9
10
11
12
13
window.onload = function() {
var oTxt1 = document.getElementById('txt1');
var oTxt2 = document.getElementById('txt2');

oTxt1.onkeydown = function(ev) {
var oEvent = ev || event;
if (oEvent.keyCode == 13 && oEvent.ctrlKey) //keyCode==13 就是等于按回车键
{
oTxt2.value += oTxt1.value + '\n';
oTxt1.value = '';
}
};
};

Console 的特殊用法

显示表格模式:

1
2
3
4
5
6
7
8
let args = ["%c Environment %c production ",
"padding: 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060;",
"padding: 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e;"
]

console.log(args[0], args[1], args[2])
// or
console.log.apply(this, arguments)

给输出设定样式:

1
2
3
4
5
6
7
8
9
10
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

var john = new Person("John", "Smith");
var jane = new Person("Jane", "Doe");
var emily = new Person("Emily", "Jones");

console.table([john, jane, emily], ["firstName"]);

Single Linked List Reverse/单链表逆转算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var d = {}
var c = {
next: d
}
var b = {
next: c
}
var a = {
next: b
}

f = function(head) {
if (head.next) {
f(head.next)['next'] = head; // 将递归结果的 next 指向前一个
delete head.next; // 并且删除掉
}
return head;
}
f(a)

分析流程

1
2
3
4
5
// 我们的目的
d.next = c
c.next = b
b.next = a
a.next = undefined

可以看到 [x.next].next = [x]
上方两个变量可以推得一个函数

1
2
3
4
5
f(x) {
f(x.next).next = x;
//我们将函数递归点放到了最前端, 这样可以一次性递归到最后一个元素
return x
}

我们需要一个跳出条件:

1
2
3
4
5
6
f = function(x) {
if (x.next) {
f(x.next).next = x;
}
return x
}

然后我们需要清除原始数据

1
2
3
4
5
6
7
f = function(head) {
if (head.next) {
f(head.next)['next'] = head; // 将递归结果的 next 指向前一个
delete head.next; // 并且删除掉
}
return head;
}

Promise

数组里面实现 Async 操作

1
2
3
4
5
6
7
8
9
10
var promises = [obj1, obj2].map(function(obj){
return db.query('obj1.id').then(function(results){
obj1.rows = results
return obj1
})
})

Promise.all(promises).then(function(results) {
console.log(results)
})

以及下方是一个 ts 实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const getPrices = async (items)=>{
const itemPrice: {
number: any
quantity: number
price: any
}[] = await Promise.all(
items.map(async e => {
const { data } = await getPrice({
variables: {
number: e.number,
quantity: e.quantity
}
})
return data
})
)
}

这里使用了两组 async-await, 因为在外部也是一个延时请求

关于 Promise.all 的 Catch

有个地方必须要注意的是, 一旦他数中任何一个 promise 失败了, 那么整个流程就会跳转到 catch

那就意味着:

  1. 如果所有的 Promise 请求成功, 进入下一个 then
  2. 如果任何一个 Promise 请求失败, 进入 Catch
    • 这一点可能会造成一些麻烦,因为这样子可能无法 track 后续的 Promise

解决方法就是 Promise 本体里面 catch 掉对应的 Error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

var request = async () => {
try {
return {
data: axios("/api/xxx"),
errorMsg: "",
};
} catch (error) {
return {
data: undefined,
errorMsg: error,
};
}
};

Promise.all([request(), request(), request(), request()])
.then((res) => {
// 继续处理 res
})
.catch((error) => {
// 因为 request() 自身进行了 catch 所以就完全不会进到这里, 防止因为一个 reject 而导致后续请求无法 track
});

NodeJS

File Stream IO

1
2
3
4
5
6
7
8
9
10
/* Read the file */
const readStream = fs.createReadStream('fakepath/input.png')

/* Sometimes read stream can be created from 3rd lib */
// const readStream = file.createReadStream()

const writeStream = fs.createWriteStream('fakepath/output.png')

/* Convert stream to file */
readStream.pipe(writeStream)