funcreader() { for data := range producerToRead { fileData, err := ioutil.ReadFile(data.fullFilename) if err != nil { log.Println("error occurs when processing", data.fullFilename, err) continue } data.fileString = string(fileData)
readToReplace <- data } }
funcreplacer() { for data := range readToReplace { data.fileString = strings.Replace(data.fileString, "http://", "https://", -1) replaceToWrite <- data } }
funcwriteer() { for data := range replaceToWrite {
if err := ioutil.WriteFile(data.fullFilename, []byte(data.fileString), 0644); err != nil { log.Println("error occurs when processing", data.fullFilename, err) return } writeToComplete <- data } }
funccomplete() { for data := range writeToComplete { log.Println("finish processing", data.fullFilename, "[", data.thisCount, "]") } }
classListimplementsIterable{ // nested class classListIteratorimplementsIterator{ int i = 0; int max = 10; public Object next(){ return i++; } publicbooleanhasNext(){ return i > max; } } public Iterator iterator(){ returnnew ListIterator(); } }
这样,就可以 iterate 一个 List 了:
1 2 3 4
List list = new List(); for (Object i : list) { // ... }
在 javascript 中也不例外,这样实现一个 Iterable :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
var iterable = { [Symbol.iterator]: function() { var i = 0; var iterator = { next: function () { var iteratorResult = { done: i > 10, value: i++ }; return iteratorResult; } }; return iterator; } };
for (let item of iterable) { console.log(item); }
协程
协程是一种抽象方式,可以让一个函数中途暂停返回一些东西,然后过一段时间后再继续执行。
1 2 3 4 5 6 7 8 9
functionroutine() local i = 0 i = i + 1 coroutine.yield(i) i = i + 1 coroutine.yield(i) i = i + 1 coroutine.yield(i) end
function runner(getIterator) { var iterator = getIterator(); function next(data) { var result = iterator.next(data); if (result.done){ return; } var promise = result.value; promise.then(function (data) { next(data); }); } next(); };
拓展篇
1. 在 NodeJS 中避免大规模计算
Javascript 只有一根线程,如果用 for 循环来计算 10000 个数字的和,整个 vm 都非卡死不行。
以前大家都用 setTimeout / setInterval 来把运算拆开来做:
1 2 3 4 5 6 7 8 9 10 11
let output = $('.power'); functionrun2() { var i = 0, end = 10000; var cancel = setInterval(function () { let p = i * i; output.append(`<p>${p}</p>`); if (++i >= end) { clearInterval(cancel); } }, 0); }
现在可以用 await 了
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functiongetPower(x) { returnnewPromise(function (resolve, reject) { setTimeout(function () { resolve(x * x); }, 0); }); } asyncfunctionrun() { let output = $('.power'); for (let i = 0; i < 10000; i++) { let p = await getPower(i); output.append(`<p>${p}</p>`); } }
functionparseRequestPayload(payload) if payload:byte(1) ~= SocksVersion then returnnil, Errors.VersionError end
local request = { version = SocksVersion, command = CommandType.Connect, addressType = AddressType.IPv4, distAddress = '', distPort = 0, }
if payload:byte(2) > CommandType.Udp then returnnil, Errors.CommandTypeNotSupported else request.command = payload:byte(2) end
local requestAddressType = payload:byte(4) if requestAddressType ~= AddressType.IPv4 and requestAddressType ~= AddressType.DomainName and requestAddressType ~= AddressType.IPv6 then returnnil, Errors.AddressTypeNotSupported else request.addressType = requestAddressType end
local portIndex if request.addressType == AddressType.IPv4 then local ipBytes = {payload:byte(5, 8)} request.distAddress = table.concat(ipBytes, '.') portIndex = 9 elseif request.addressType == AddressType.DomainName then locallen = payload:byte(5) request.distAddress = payload:sub(6, 6 + len - 1) portIndex = 5 + len + 1 elseif request.addressType == AddressType.IPv6 then returnnil, Errors.AddressTypeNotSupported end