欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

測試驅(qū)動ChatGPT編程示例詳解

 更新時間:2023年03月23日 09:55:19   作者:仝鍵  
這篇文章主要為大家介紹了測試驅(qū)動ChatGPT編程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

有輸入就要有輸出

上一篇文章中,我故意漏掉了一個手法沒有講。具體是什么樣的手法呢?其實在實施的過程中,我發(fā)現(xiàn)把主干流程的邏輯講的再清楚,他生成的時候還是會有很多錯誤,改進(jìn)自己的描述已經(jīng)讓我覺得有些煩躁了。我不由得想起了2023年1月,ECM發(fā)了一篇文章:《The End of Programming》以呼應(yīng)ChatGPT的誕生,在文章的最后寫道:

我們正在迅速走向這樣一個世界:計算的基本構(gòu)件是有脾氣的、神秘的、自適應(yīng)的代理。

好家伙,克蘇魯神話的味都出來了,世界的底層是混亂與瘋狂是嗎?所以ChatGPT就是是活化的隱匿賢者?^_^

玩完梗我們回來看這個事情啊,突然我意識到,是不是我之前的prompt還缺了一些東西?我只給了輸入和主干邏輯,我沒有給他輸出啊。在我的視角里,可能這個輸入通過這個主干邏輯只能有一種結(jié)果,但是對于AI來說,也未必?。▌e說AI了,我跟另一個初級開發(fā)這么講,他都未必能寫出一種結(jié)果來,只能說這個行為表現(xiàn)太人類了)。如果我把輸出也給他是不是可以讓他寫的更好一點,于是我把我的prompt改成了下面的描述:

我想用nodeJS用下面的yaml描繪的數(shù)據(jù)結(jié)構(gòu)得到一個新的數(shù)組:

base:
  steps: 10
  batch_size: 1
  poly:
- template_prompt:
    template: >
        a cat,
        ${ chara }
        ${ facial_expressions }
    meta:
      - chara: #  這里改成了數(shù)組
        - Abyssinian,
        - cat_in_boots,
      facial_expressions:
        - (smile:1.5),  
        - (smile:1.2),  
        - smile, 
    steps: 20

可能的輸出:

[
{
    steps: 20,
    prompt: 'a cat,\nAbyssinian,\n(smile:1.5),\n',
    batch_size: 1
},
{
    steps: 20,
    prompt: 'a cat,\nAbyssinian,\n(smile:1.2),\n',
    batch_size: 1
},
{
    steps: 20,
    prompt: 'a cat,\nAbyssinian,\nsmile,\n',
    batch_size: 1
},
{
    steps: 20,
    prompt: 'a cat,\ncat_in_boots,\n(smile:1.5),\n',
    batch_size: 1
},
{
    steps: 20,
    prompt: 'a cat,\ncat_in_boots,\n(smile:1.2),\n',
    batch_size: 1
},
{
    steps: 20,
    prompt: 'a cat,\ncat_in_boots,\nsmile,\n',
    batch_size: 1
},  
]

要求:

假設(shè)上面的yaml轉(zhuǎn)成json的轉(zhuǎn)換代碼我已經(jīng)寫完了

我需要遍歷poly下的所有的頂層元素

遍歷過程中,要處理template_prompt元素的子元素:

從template中讀取作為模版。

讀取meta中的屬性,因為屬性可能每次都不一樣,是不確定的,所以不能硬編碼。

然后基于meta中的屬性,把template作為 string literal 解析,這個解析代碼我已經(jīng)有了,假設(shè)名為render_string_template,可以不實現(xiàn),留一個函數(shù)接口即可。

要遍歷組合meta中的每一個屬性組形成一個數(shù)組,

每一個屬性組可能只需要看做一個對象,當(dāng)且僅當(dāng)每一個屬性值都為單值

每一個屬性組可能也需要展開,當(dāng)且僅當(dāng)任何一個屬性值有多值,比如 facial_expressions 有一個值,chara有兩個值,那么應(yīng)該生成1*2也就是兩組屬性放入這個數(shù)組中,這個數(shù)組和template會被傳入render_string_template函數(shù),最后會獲得兩個prompt字符串

將生成的個prompt字符串?dāng)?shù)組和template_prompt元素之外的其他元素合并成一個對象,要求在同一級別。prompt字符串?dāng)?shù)組有幾個元素,就會合并成幾個對象,并放入一個新數(shù)組中,我們稱之為ploys。

繼續(xù)遍歷,直到遍歷完所有頂層元素,所有元素都放入了polys中。polys是一個一維數(shù)組。

將ploys中的每一個元素與base中的屬性合成一個新的對象,base的屬性展開與prompt屬性同級,當(dāng)ploys中的每一個元素的屬性名與base中的屬性名相同時,覆蓋base中的屬性。這些新對象組合出的數(shù)組就是我要的數(shù)組

果然就得到了預(yù)期的結(jié)果。

這一個動作,讓我打開了思路,用輸入+輸出框住它生成的邊界還是挺好用的。輸入+輸出框住邊界?這不就是測試嗎?

停下來想一想

從我們的體驗來看,確實啊,ChatGPT生成的是有點不穩(wěn)定。《The End of Programming》說的沒錯,底層確實有點混亂與瘋狂的味道,起碼不太穩(wěn)定。但這事也就聽起來很嚇人,說實在的,人就比ChatGPT穩(wěn)定多少呢?我這個人比較粗心大意,我寫代碼的時候也經(jīng)常腦子一抽,寫出一些事后看自己都想抽自己的腦殘錯誤,所以我自打聽說了TDD,很快就變成了堅定地TDD原教旨主義者,沒有TDD的世界對我們這種人來說本來就是混亂與瘋狂的,要說駕馭軟件開發(fā)過程中的混亂與瘋狂,那你是問對人了。

那么回顧一下TDD是什么?下面是一個復(fù)雜版

基本上就是,先寫一個測試用例,然后執(zhí)行,得到期望的失敗,什么是期望的失敗呢,比如說,你寫了一個add函數(shù),接受兩個參數(shù),然后你寫了一個add(1,1),你期望的失敗可能是返回某個值,他不等于2,實際你執(zhí)行的時候呢,報錯,說add函數(shù)不存在,這就不是你期望的失敗。你要調(diào)整環(huán)境到你期望的失敗,然后開始寫實現(xiàn),寫完實現(xiàn)再執(zhí)行,如果測試不通過了,就接著改實現(xiàn),直到通過。如果通過了,就問自己要不要重構(gòu),如果要重構(gòu),就改實現(xiàn),改完的還要通過測試,如果不想重構(gòu)了,那就寫下一個測試用例??傊褪沁@么個往復(fù)循環(huán)的流程。

如果上面那個復(fù)雜版讓你覺得很暈?zāi)兀梢钥催@個簡單版:

紅表示測試執(zhí)行失敗,綠表示測試執(zhí)行通過,重構(gòu)就不用解釋了。所以永遠(yuǎn)是綠了重構(gòu),重構(gòu)完可能紅可能綠,紅了就讓他變綠。只有變綠后,可以開始下一次循環(huán)。

上面這些圖講的是TDD的過程,我個人覺得更核心的是,在實現(xiàn)代碼的這個過程中,你同時生產(chǎn)了一套自動化測試,他可以在你將來不管是加新功能還是修Bug還是重構(gòu),都不會陷入按下葫蘆起來瓢的窘境。那么在ChatGPT的時代,這個方法還能用嗎?總感覺哪里需要修改一下,不過沒關(guān)系,我們先走起來,邊走邊想。

想好了,繼續(xù)出發(fā)

那么既然是TDD,應(yīng)該先寫測試,但是我實現(xiàn)都寫完了啊。算了,這也是大多數(shù)項目的現(xiàn)狀,那就先補(bǔ)個測試吧。但是補(bǔ)測試是個很煩的事情啊,我靈機(jī)一動,要不……讓ChatGPT給我搞?它能行嗎?誰知道呢,試試又不花錢。 于是我就說:

給下面代碼設(shè)計一些測試用例:

module.exports = function render_my_yaml_dsl(data){
const vm = require('vm');
- // 定義一個函數(shù)用于渲染字符串模板
function render_string_template(originalScriptTemplate, intention) {
    // console.log(intention);
    // 省略渲染代碼
    const execScriptTemplate = "`" + originalScriptTemplate + "`";
- const script = new vm.Script(execScriptTemplate);
    const execScript = script.runInNewContext(intention);
    // console.debug(execScript);
    return execScript;
}
- // 定義一個函數(shù)用于展開屬性組合
function expand_attributes(attributes) {
    const result = [];
    attributes.forEach(obj => {
        Object.values(obj).forEach(val => {
            if (Array.isArray(val)) {
                val.forEach(v => {
                    result.push({ ...obj, [Object.keys(obj).find(key => obj[key] === val)]: v });
                });
            } else {
                result.push(obj);
            }
        });
    });
    return result;
}
- const polys = [];
- for (const poly of data.poly) {
    const { template_prompt, ...other } = poly;
    const { template, meta } = template_prompt;
- const variableGroups = expand_attributes(meta);
    const prompts = variableGroups.map(variables => render_string_template(template, variables));
- for (const prompt of prompts) {
        polys.push({ prompt, ...other });
    }
}
- const result = polys.map(poly => ({ ...data.base, ...poly }));
return result;
}

是的就是這么任性,代碼直接扔給他。然后我得到了下面的回復(fù):

以下是一些可能的測試用例:

  • 當(dāng)輸入?yún)?shù) data 為空對象時,函數(shù)是否能正常運行并返回一個空數(shù)組?
  • 當(dāng)輸入?yún)?shù) data.poly 為空數(shù)組時,函數(shù)是否能正常運行并返回一個空數(shù)組?
  • 當(dāng)輸入?yún)?shù) data.poly 不包含任何屬性組合時,函數(shù)是否能正常運行并返回一個包含原始數(shù)據(jù)的數(shù)組?
  • 當(dāng)輸入?yún)?shù) data.poly 包含一個屬性組合時,函數(shù)是否能正常運行并返回一個包含根據(jù)屬性組合渲染的數(shù)據(jù)的數(shù)組?
  • 當(dāng)輸入?yún)?shù) data.poly 包含多個屬性組合時,函數(shù)是否能正常運行并返回一個包含根據(jù)所有屬性組合渲染的數(shù)據(jù)的數(shù)組?
  • 當(dāng)模板中的字符串模板包含模板變量時,函數(shù)是否能正常運行并渲染模板變量?
  • 當(dāng)模板中的字符串模板包含 JavaScript 代碼時,函數(shù)是否能正常運行并執(zhí)行 JavaScript 代碼?
  • 當(dāng)屬性組合中包含數(shù)組時,函數(shù)是否能正常運行并正確展開屬性組合?
  • 當(dāng)屬性組合中包含對象時,函數(shù)是否能正常運行并正確展開屬性組合?
  • 當(dāng)輸入?yún)?shù) data.base 中包含對象時,函數(shù)是否能正常運行并將 data.base 和渲染的屬性組合合并為一個對象?

我嘆了口氣,我在期望什么,果然是這么泛泛的片湯話嗎?這玩意還用你告訴我?而且,你這里面還有些不是我想要的啊。唉……心中抱怨了一陣后,我還是不死心,我繼續(xù)說:

分別準(zhǔn)備一些數(shù)據(jù)

這個要求仿佛打開了潘多拉的盒子,我得到了下面的輸出:

以下是可能的數(shù)據(jù)準(zhǔn)備:

  • 空對象:
const data = {};
  • 空的 poly 數(shù)組:
const data = {
poly: []
};
  • 包含一個屬性組合的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name}: ${price}',
     meta: [
       { name: 'color', value: ['red', 'blue'] },
       { name: 'price', value: [10, 20] }
     ]
   },
   id: 1
 }
]
};
  • 包含多個屬性組合的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name}: ${price}',
     meta: [
       { name: 'color', value: ['red', 'blue'] },
       { name: 'price', value: [10, 20] }
     ]
   },
   id: 1
 },
 {
   template_prompt: {
     template: '${name} (${size}): ${price}',
     meta: [
       { name: 'size', value: ['S', 'M', 'L'] },
       { name: 'price', value: [30, 40, 50] }
     ]
   },
   id: 2
 }
]
};
  • 包含模板變量和 JavaScript 代碼的字符串模板的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name}: ${price + tax}',
     meta: [
       { name: 'color', value: ['red'] },
       { name: 'price', value: [10] },
       { name: 'tax', value: [2] }
     ]
   },
   id: 1
 }
]
};
  • 包含數(shù)組和對象的屬性組合的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name} (${color.name}): ${price}',
     meta: [
       { color: { name: 'red', code: '#ff0000' }, price: [10] },
       { color: { name: 'blue', code: '#0000ff' }, price: [20] }
     ]
   },
   id: 1
 }
]
};
  • 包含屬性值為數(shù)組,但未包含數(shù)組元素的屬性組合的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name} (${color}): ${price}',
     meta: [
       { color: ['red'], price: [10] },
       { color: ['blue'], price: [20] }
     ]
   },
   id: 1
 }
]
};
  • 包含模板變量為屬性值的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${props.name}: ${props.price}',
     meta: [
       { props: { name: 'Product B', price: 30 } }
     ]
   },
   id: 1
 }
]
};
  • 包含 render_string_template 函數(shù)中 console.log 調(diào)用的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name}: ${price}',
     meta: [
       { name: 'color', value: ['red', 'blue'] },
       { name: 'price', value: [10, 20] }
     ]
   },
   id: 1
 }
]
};
console.log(render_my_yaml_dsl(data));
  • 包含 expand_attributes 函數(shù)中未包含數(shù)組的屬性組合的數(shù)據(jù):
const data = {
base: {
 id: 1,
 name: 'Product A'
},
poly: [
 {
   template_prompt: {
     template: '${name} (${color}): ${price}',
     meta: [
       { color: 'red', price: [10] },
       { color: 'blue', price: [20] }
     ]
   },
   id: 1
 }
]
};

這一刻,我仿佛聽到了什么出現(xiàn)裂紋的聲音,是我的飯碗嗎^_^。

我曾經(jīng)愚蠢的以為,當(dāng)我們有了ChatGPT這么強(qiáng)大的工具后,我們只需要寫測試就可以了,讓他去寫實現(xiàn),而我沒有發(fā)現(xiàn)這個邏輯里面一個愚蠢的漏洞,一個AI都能寫實現(xiàn)了,為什么他寫不了測試呢?反過來講,有很多客戶問我有沒有自動生成自動化測試的工具,因為他們不想寫測試,現(xiàn)在也一樣尷尬了。好消息是,有,壞消息是,實現(xiàn)他也能寫。

激動了一會,我漸漸冷靜下來了,沒事沒事,這測試沒法直接用啊,對吧,你看這測試難道還能扔給一個框架讓他自動運行嗎,那不是還要寫一個專用框架………………想到這,我意識到……好像……我在第一篇的時候干過這事……然后我懷著忐忑的心,寫下了下面的prompt:

我們的文件夾結(jié)構(gòu)如下所示

.
├── index.js
└── test
├── cases
│   ├── 1.input.json
│   ├── 1.output.json
│   ├── 2.input.json
│   ├── 2.output.json
│   ├── 3.input.json
│   ├── 3.output.json
│   ├── 4.input.json
│   └── 4.output.json
└── index.js

index.js 是一個函數(shù),大概如下:

module.exports = function render_my_yaml_dsl(data){
//....
}

test/cases下是所有的測試數(shù)據(jù),input和output為一組,比如1.input.json存儲了一個測試的描述和given數(shù)據(jù),1.output.json存儲了一個測試的expect數(shù)據(jù)。兩者在.input或.output之前的字符串完全相等為一組。 input.json數(shù)據(jù)結(jié)構(gòu)為:

    {
    "desc": "測試用例描述",
    "data": { //具體的測試數(shù)據(jù)
            }
    }

output.json則全部為具體的測試數(shù)據(jù) 基于這個文件夾結(jié)構(gòu)寫一個測試框架,放在test/index.js里,要求:

可以遍歷test/cases下的文件,分組執(zhí)行且互相不干擾,也就是其中一組失敗了也會繼續(xù)運行下一組,只是會打印出錯誤信息。

可以在上層文件夾執(zhí)行node test來執(zhí)行

讀取文件的fs,要使用const fs = require('fs/promise')引入。

用assert庫進(jìn)行斷言

每執(zhí)行一個測試,要打印一個提示,提示的部分內(nèi)容要來自input.json 中的desc 給出這個代碼

然后我得到了下面的代碼:

可以使用以下代碼實現(xiàn)測試框架:

const assert = require('assert');
const fs = require('fs/promises');
const path = require('path');
const render_my_yaml_dsl = require('../index');
const testDir = path.join(__dirname, 'cases');
async function runTests() {
    const files = await fs.readdir(testDir);
    for (const file of files) {
        if (!file.endsWith('.input.json')) {
            continue;
        }
        const caseName = path.basename(file, '.input.json');
        const input = await fs.readFile(path.join(testDir, `${caseName}.input.json`), 'utf8');
        const output = await fs.readFile(path.join(testDir, `${caseName}.output.json`), 'utf8');
        const { desc, data } = JSON.parse(input);
        console.log(`Running test "${desc}"`);
        try {
            const result = render_my_yaml_dsl(data);
            assert.deepStrictEqual(result, JSON.parse(output));
            console.log(`Test "${desc}" passed`);
        } catch (error) {
            console.error(`Test "${desc}" failed`);
            console.error(error);
        }
    }
}
runTests();

解釋:

  • 首先引入 assert 和 fs 模塊,并且導(dǎo)入需要測試的函數(shù) render_my_yaml_dsl。
  • 定義測試文件夾路徑 testDir。
  • 創(chuàng)建一個異步函數(shù) runTests 來遍歷測試文件夾下的所有測試用例。
  • 使用 fs.readdir 異步讀取測試文件夾下的所有文件,然后遍歷文件數(shù)組,只選擇以 .input.json 結(jié)尾的文件,跳過其他文件。
  • 通過 path.basename 函數(shù)獲取測試用例的名稱,然后使用 fs.readFile 異步讀取該測試用例的輸入和輸出文件,并使用 JSON.parse 解析 JSON 格式的數(shù)據(jù)。
  • 在控制臺中打印正在運行的測試用例的描述 desc。
  • 使用 try...catch 語句運行測試用例,并使用 assert.deepStrictEqual 函數(shù)斷言測試結(jié)果是否與期望值相等。如果測試通過,打印成功信息,否則打印錯誤信息。
  • 最后調(diào)用 runTests 函數(shù)運行測試。

這一刻我終于確信,那確實是飯碗出現(xiàn)裂紋的聲音。(雖然上面的只有輸入,但是后來我讓他給出輸出,他也給出了,反正測試框架都有了,大不了跑一遍就有了所有的輸出了嘛,所以這不是啥大問題。)

有了這個框架之后,我工作流程大概變成了這么個節(jié)奏:

  • 告訴他,我要擴(kuò)展新功能,然后扔給他舊代碼,接著告訴他這里是新新功能需要的輸入,我期望的輸出是什么。邊界是什么,現(xiàn)在給我代碼。

然后執(zhí)行新加的測試,

如果新測試不通過,就讓他重新生成.

如果新加測試通過了,但是舊的測試廢了,就把就廢了測試配上代碼給他,告訴他代碼有Bug,這是以前的輸入,期望的輸出是什么,你現(xiàn)在的輸出是什么,讓他改代碼。 整個過程就很像TDD的紅-綠循環(huán),雖然重構(gòu)沒有了,但是紅綠循環(huán)還是有的。 而更過分的是,一開始新功能需要的測試用例我都懶得自己寫,我就大概告訴他要搞個什么樣的擴(kuò)展,給他代碼和舊得測試用例結(jié)構(gòu),讓他給我寫個新的測試用例。然后就給我寫出來了。(也不總能很完美,但是就是需要改也比以前快了不知道多少,關(guān)鍵不用去想那些繁瑣的細(xì)節(jié)也是提供了一定程度的情緒價值。)

按照我的工作流程畫個人在回路是這樣的:

總結(jié)一下

開篇我們從一個上一篇漏掉的關(guān)鍵手法開始,了解到輸入和輸出配合可以讓ChatGPT寫出的代碼更靠譜,而且對于主干流程的描述可以不用那么復(fù)雜。

接著我們發(fā)現(xiàn),這確定了輸入輸出就很像測試,那么我們是不是可以用測試驅(qū)動的方式驅(qū)動ChatGPT開發(fā)呢?經(jīng)過一番嘗試我們得到了一個可以用于ChatGPT的類TDD工作方式。并畫出了整個人在回路。

這個回路很像TDD,但在這個回路里,我們既不需要寫測試,也不需要寫實現(xiàn),我們主要的工作是保證ChatGPT在按照整個TDD的流程在寫代碼。因為TDD屬于XP(極限編程)的核心實踐,所以我們開玩笑說,參照Scrum Master,我們以后可以叫自己XP Master。被人提醒Master會被沖,那我們就叫自己 XP Shifu 吧。(典出功夫熊貓^_^)

目前受制于GPT3.5的3000多字的限制,只能一個個用例讓他改,等GPT4的3萬多字成為常態(tài)后,這個工作方法只會更強(qiáng)大,甚至可以考慮某種程度的自動化。因為我們可以看到,人在回路上只有一個環(huán)節(jié)需要人參與,其他的都可以不需要。這就是我們上篇文章中提到的,可以自動化的一種思路,有想做工具的可以考慮一下,我還挺需要這么個工具的。

整個用ChatGPT編程的思路到這里主干就講的差不多了,接下來我們會講一些細(xì)分場景的套路。然后如果有時間的話,就把派發(fā)引擎和自動化工具也試著做一做

以上就是測試驅(qū)動ChatGPT編程示例詳解的詳細(xì)內(nèi)容,更多關(guān)于測試驅(qū)動ChatGPT編程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Node.js事件驅(qū)動

    Node.js事件驅(qū)動

    Node.Js是基于javascript語言,建構(gòu)在google V8 engine以及Linux上的一個非阻塞事件驅(qū)動IO框架。這里主要不是介紹nodejs具體應(yīng)用代碼,而是想介紹一下事件驅(qū)動編程。
    2015-06-06
  • npm?list輸出結(jié)果包含extraneous標(biāo)志記錄分析

    npm?list輸出結(jié)果包含extraneous標(biāo)志記錄分析

    這篇文章主要為大家介紹了npm?list輸出結(jié)果包含extraneous標(biāo)志記錄分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • node.js下LDAP查詢實例分享

    node.js下LDAP查詢實例分享

    這篇文章主要介紹了node.js下LDAP查詢實例分享的相關(guān)資料,需要的朋友可以參考下
    2015-09-09
  • nodejs利用ajax實現(xiàn)網(wǎng)頁無刷新上傳圖片實例代碼

    nodejs利用ajax實現(xiàn)網(wǎng)頁無刷新上傳圖片實例代碼

    本篇文章主要介紹了nodejs利用ajax實現(xiàn)網(wǎng)頁無刷新上傳圖片實例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • express框架通過ejs模板渲染輸出頁面實例分析

    express框架通過ejs模板渲染輸出頁面實例分析

    這篇文章主要介紹了express框架通過ejs模板渲染輸出頁面的方法,結(jié)合實例形式分析了express框架使用ejs模版引擎渲染輸出的相關(guān)操作技巧與使用注意事項,需要的朋友可以參考下
    2023-05-05
  • Node.js+Express配置入門教程詳解

    Node.js+Express配置入門教程詳解

    下面小編就為大家?guī)硪黄狽ode.js+Express配置入門教程詳解。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • nodejs實現(xiàn)獲取當(dāng)前url地址及url各種參數(shù)值

    nodejs實現(xiàn)獲取當(dāng)前url地址及url各種參數(shù)值

    這篇文章主要介紹了nodejs實現(xiàn)獲取當(dāng)前url地址及url各種參數(shù)值,本文直接給出代碼實例,需要的朋友可以參考下
    2015-06-06
  • 詳解Node.js異步處理的各種寫法

    詳解Node.js異步處理的各種寫法

    這篇文章主要介紹了Node.js異步處理的各種寫法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-06-06
  • node.js中的buffer.length方法使用說明

    node.js中的buffer.length方法使用說明

    這篇文章主要介紹了node.js中的buffer.length方法使用說明,本文介紹了buffer.length的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • node.js中的buffer.Buffer.isEncoding方法使用說明

    node.js中的buffer.Buffer.isEncoding方法使用說明

    這篇文章主要介紹了node.js中的buffer.Buffer.isEncoding方法使用說明,本文介紹了buffer.Buffer.isEncoding的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12

最新評論